X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTableWidget.java;h=3052ae95811a21a0e6cd1bf85dc9918dc5b71365;hb=4f4042d69616c1881c1bbdca12720b57e6121d0d;hp=32f3e55ac5d95926b002c02c256e35810cbd3469;hpb=9c1720164b004d462af8284c21fb2666e2affd63;p=fanfix.git diff --git a/src/jexer/TTableWidget.java b/src/jexer/TTableWidget.java index 32f3e55..3052ae9 100644 --- a/src/jexer/TTableWidget.java +++ b/src/jexer/TTableWidget.java @@ -28,11 +28,15 @@ */ package jexer; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import jexer.bits.CellAttributes; import jexer.event.TKeypressEvent; import jexer.event.TMenuEvent; +import jexer.event.TMouseEvent; +import jexer.event.TResizeEvent; import jexer.menu.TMenu; import static jexer.TKeypress.*; @@ -76,6 +80,26 @@ public class TTableWidget extends TWidget { THICK, } + /** + * Row label width. + */ + private static final int ROW_LABEL_WIDTH = 8; + + /** + * Column label height. + */ + private static final int COLUMN_LABEL_HEIGHT = 1; + + /** + * Extra rows to add. + */ + private static final int EXTRA_ROWS = 10; + + /** + * Extra columns to add. + */ + private static final int EXTRA_COLUMNS = 10 * (8 + 1); + // ------------------------------------------------------------------------ // Variables -------------------------------------------------------------- // ------------------------------------------------------------------------ @@ -113,18 +137,33 @@ public class TTableWidget extends TWidget { /** * If true, highlight the entire row of the currently-selected cell. */ - private boolean highlightRow = true; + private boolean highlightRow = false; /** * If true, highlight the entire column of the currently-selected cell. */ - private boolean highlightColumn = true; + private boolean highlightColumn = false; /** * If true, show the row labels as the first column. */ private boolean showRowLabels = true; + /** + * If true, show the column labels as the first row. + */ + private boolean showColumnLabels = true; + + /** + * The top border for the first row. + */ + private Border topBorder = Border.NONE; + + /** + * The left border for the first column. + */ + private Border leftBorder = Border.NONE; + /** * Column represents a column of cells. */ @@ -143,12 +182,12 @@ public class TTableWidget extends TWidget { /** * Column label. */ - private String label; + private String label = ""; /** - * The border for this column. + * The right border for this column. */ - private Border border = Border.NONE; + private Border rightBorder = Border.NONE; /** * Constructor sets label to lettered column. @@ -209,9 +248,9 @@ public class TTableWidget extends TWidget { private String label = ""; /** - * The border for this row. + * The bottom border for this row. */ - private Border border = Border.NONE; + private Border bottomBorder = Border.NONE; /** * Constructor sets label to numbered row. @@ -302,7 +341,7 @@ public class TTableWidget extends TWidget { this.column = column; this.row = row; - field = addField(0, 0, width - 1, false); + field = addField(0, 0, width, false); field.setEnabled(false); field.setBackgroundChar(' '); } @@ -311,6 +350,66 @@ public class TTableWidget extends TWidget { // Event handlers ----------------------------------------------------- // -------------------------------------------------------------------- + /** + * Handle mouse double-click events. + * + * @param mouse mouse double-click event + */ + @Override + public void onMouseDoubleClick(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + // Double-click means to start editing. + fieldText = field.getText(); + isEditing = true; + field.setEnabled(true); + activate(field); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(false); + } + } + + /** + * Handle mouse press events. + * + * @param mouse mouse button press event + */ + @Override + public void onMouseDown(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(false); + } + } + + /** + * Handle mouse release events. + * + * @param mouse mouse button release event + */ + @Override + public void onMouseUp(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(false); + } + } + /** * Handle keystrokes. * @@ -382,6 +481,8 @@ public class TTableWidget extends TWidget { field.setInactiveColorKey("ttable.inactive"); } + assert (isVisible() == true); + super.draw(); } @@ -433,34 +534,75 @@ public class TTableWidget extends TWidget { // Place a grid of cells that fit in this space. int row = 0; - for (int i = 0; i < height; i += rows.get(0).height) { + for (int i = 0; i < height + EXTRA_ROWS; i += rows.get(0).height) { int column = 0; - for (int j = 0; j < width; j += columns.get(0).width) { + for (int j = 0; j < width + EXTRA_COLUMNS; + j += columns.get(0).width) { + Cell cell = new Cell(this, j, i, columns.get(0).width, rows.get(0).height, column, row); cell.setText("" + row + " " + column); rows.get(row).add(cell); columns.get(column).add(cell); - if ((i == 0) && (j + columns.get(0).width < width)) { + if ((i == 0) && + (j + columns.get(0).width < width + EXTRA_COLUMNS) + ) { columns.add(new Column(column + 1)); } column++; } - if (i + rows.get(0).height < height) { + if (i + rows.get(0).height < height + EXTRA_ROWS) { rows.add(new Row(row + 1)); } row++; } activate(columns.get(selectedColumn).get(selectedRow)); - alignGrid(); + alignGrid(true); + + // Set the menu to match the flags. + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS). + setChecked(showRowLabels); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS). + setChecked(showColumnLabels); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW). + setChecked(highlightRow); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN). + setChecked(highlightColumn); + + } // ------------------------------------------------------------------------ // Event handlers --------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Handle mouse press events. + * + * @param mouse mouse button press event + */ + @Override + public void onMouseDown(final TMouseEvent mouse) { + if (mouse.isMouseWheelUp() || mouse.isMouseWheelDown()) { + // Treat wheel up/down as 3 up/down + TKeypressEvent keyEvent; + if (mouse.isMouseWheelUp()) { + keyEvent = new TKeypressEvent(kbUp); + } else { + keyEvent = new TKeypressEvent(kbDown); + } + for (int i = 0; i < 3; i++) { + onKeypress(keyEvent); + } + return; + } + + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + } + /** * Handle keystrokes. * @@ -482,40 +624,74 @@ public class TTableWidget extends TWidget { return; } + boolean forceGridAlign = false; + if (keypress.equals(kbLeft)) { + // Left if (selectedColumn > 0) { selectedColumn--; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbRight)) { + // Right if (selectedColumn < columns.size() - 1) { selectedColumn++; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbUp)) { + // Up if (selectedRow > 0) { selectedRow--; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbDown)) { + // Down if (selectedRow < rows.size() - 1) { selectedRow++; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbHome)) { + // Home - leftmost column selectedColumn = 0; activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else if (keypress.equals(kbEnd)) { + // End - rightmost column selectedColumn = columns.size() - 1; activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else if (keypress.equals(kbPgUp)) { - // TODO + // PgUp - Treat like multiple up + for (int i = 0; i < getHeight() - 2; i++) { + if (selectedRow > 0) { + selectedRow--; + } + } + activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else if (keypress.equals(kbPgDn)) { - // TODO + // PgDn - Treat like multiple up + for (int i = 0; i < getHeight() - 2; i++) { + if (selectedRow < rows.size() - 1) { + selectedRow++; + } + } + activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else if (keypress.equals(kbCtrlHome)) { - // TODO + // Ctrl-Home - go to top-left + selectedRow = 0; + selectedColumn = 0; + activate(columns.get(selectedColumn).get(selectedRow)); + activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else if (keypress.equals(kbCtrlEnd)) { - // TODO + // Ctrl-End - go to bottom-right + selectedRow = rows.size() - 1; + selectedColumn = columns.size() - 1; + activate(columns.get(selectedColumn).get(selectedRow)); + activate(columns.get(selectedColumn).get(selectedRow)); + forceGridAlign = true; } else { // Pass to the Cell. super.onKeypress(keypress); @@ -523,7 +699,19 @@ public class TTableWidget extends TWidget { // We may have scrolled off screen. Reset positions as needed to // make the newly selected cell visible. - alignGrid(); + alignGrid(forceGridAlign); + } + + /** + * Handle widget resize events. + * + * @param event resize event + */ + @Override + public void onResize(final TResizeEvent event) { + super.onResize(event); + + alignGrid(true); } /** @@ -534,6 +722,18 @@ public class TTableWidget extends TWidget { @Override public void onMenu(final TMenuEvent menu) { switch (menu.getId()) { + case TMenu.MID_TABLE_VIEW_ROW_LABELS: + showRowLabels = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_COLUMN_LABELS: + showColumnLabels = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW: + highlightRow = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN: + highlightColumn = getApplication().getMenuItem(menu.getId()).getChecked(); + break; case TMenu.MID_TABLE_BORDER_NONE: case TMenu.MID_TABLE_BORDER_ALL: case TMenu.MID_TABLE_BORDER_RIGHT: @@ -555,40 +755,84 @@ public class TTableWidget extends TWidget { columns.get(selectedColumn).width--; for (Cell cell: getSelectedColumn().cells) { cell.setWidth(columns.get(selectedColumn).width); - cell.field.setWidth(columns.get(selectedColumn).width - 1); + cell.field.setWidth(columns.get(selectedColumn).width); } for (int i = selectedColumn + 1; i < columns.size(); i++) { for (Cell cell: columns.get(i).cells) { cell.setX(cell.getX() - 1); } } - alignGrid(); + alignGrid(false); break; case TMenu.MID_TABLE_COLUMN_WIDEN: columns.get(selectedColumn).width++; for (Cell cell: getSelectedColumn().cells) { cell.setWidth(columns.get(selectedColumn).width); - cell.field.setWidth(columns.get(selectedColumn).width - 1); + cell.field.setWidth(columns.get(selectedColumn).width); } for (int i = selectedColumn + 1; i < columns.size(); i++) { for (Cell cell: columns.get(i).cells) { cell.setX(cell.getX() + 1); } } - alignGrid(); + alignGrid(false); break; case TMenu.MID_TABLE_FILE_SAVE_CSV: + // TODO + break; case TMenu.MID_TABLE_FILE_SAVE_TEXT: + // TODO break; default: super.onMenu(menu); } + + alignGrid(false); } // ------------------------------------------------------------------------ // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Draw the table row/column labels, and borders. + */ + @Override + public void draw() { + CellAttributes labelColor = getTheme().getColor("ttable.label"); + CellAttributes labelColorSelected = getTheme().getColor("ttable.label.selected"); + CellAttributes borderColor = getTheme().getColor("ttable.border"); + + // Column labels. + if (showColumnLabels == true) { + for (int i = left; i < columns.size(); i++) { + if (columns.get(i).get(top).isVisible() == false) { + break; + } + putStringXY(columns.get(i).get(top).getX(), 0, + String.format(" %-" + + (columns.get(i).width - 2) + + "s ", columns.get(i).label), + (i == selectedColumn ? labelColorSelected : labelColor)); + } + } + + // Row labels. + if (showRowLabels == true) { + for (int i = top; i < rows.size(); i++) { + if (rows.get(i).get(left).isVisible() == false) { + break; + } + putStringXY(0, rows.get(i).get(left).getY(), + String.format(" %-6s ", rows.get(i).label), + (i == selectedRow ? labelColorSelected : labelColor)); + } + } + + // Now draw the window borders. + super.draw(); + } + // ------------------------------------------------------------------------ // TTable ----------------------------------------------------------------- // ------------------------------------------------------------------------ @@ -634,41 +878,368 @@ public class TTableWidget extends TWidget { } /** - * Get the full horizontal width of this table. + * Get the currently-selected column number. 0 is the left-most column. * - * @return the width required to render the entire table + * @return the selected column number */ - public int getMaximumWidth() { - int totalWidth = 0; - if (showRowLabels == true) { - // For now, all row labels are 8 cells wide. TODO: make this - // adjustable. - totalWidth += 8; + public int getSelectedColumnNumber() { + return selectedColumn; + } + + /** + * Set the currently-selected column number. 0 is the left-most column. + * + * @param column the column number to select + */ + public void setSelectedColumnNumber(final int column) { + if ((column < 0) || (column > columns.size() - 1)) { + throw new IndexOutOfBoundsException("Column count is " + + columns.size() + ", requested index " + column); } - for (Cell cell: getSelectedRow().cells) { - totalWidth += cell.getWidth() + 1; + selectedColumn = column; + activate(columns.get(selectedColumn).get(selectedRow)); + alignGrid(true); + } + + /** + * Get the currently-selected row number. 0 is the top-most row. + * + * @return the selected row number + */ + public int getSelectedRowNumber() { + return selectedRow; + } + + /** + * Set the currently-selected row number. 0 is the left-most column. + * + * @param row the row number to select + */ + public void setSelectedRowNumber(final int row) { + if ((row < 0) || (row > rows.size() - 1)) { + throw new IndexOutOfBoundsException("Row count is " + + rows.size() + ", requested index " + row); } - return totalWidth; + selectedRow = row; + activate(columns.get(selectedColumn).get(selectedRow)); + alignGrid(true); + } + + /** + * Get the number of columns. + * + * @return the number of columns + */ + public int getColumnCount() { + return columns.size(); + } + + /** + * Get the number of rows. + * + * @return the number of rows + */ + public int getRowCount() { + return rows.size(); } /** * Align the grid so that the selected cell is fully visible. + * + * @param force if true, always move the grid as needed */ - private void alignGrid() { + private void alignGrid(final boolean force) { + boolean resetRowY = false; + boolean resetColumnX = false; + + if (selectedColumn < left) { + left = selectedColumn; + resetColumnX = true; + resetRowY = true; + } + if (selectedRow < top) { + top = selectedRow; + resetColumnX = true; + resetRowY = true; + } + + if (force == true) { + resetRowY = true; + resetColumnX = true; + } else if ((getSelectedCell().getX() + getSelectedCell().getWidth() + 1 > + getWidth() - 1) + || (columns.get(left).get(0).getX() < + (showRowLabels == true ? ROW_LABEL_WIDTH : 0)) + ) { + resetColumnX = true; + resetRowY = true; + } else if ((getSelectedCell().getY() + getSelectedCell().getHeight() > + getHeight()) + || (rows.get(top).get(0).getY() < + (showColumnLabels == true ? COLUMN_LABEL_HEIGHT : 0)) + ) { + resetColumnX = true; + resetRowY = true; + } + + if ((resetColumnX == false) && (resetRowY == false)) { + // Nothing to do, bail out. + return; + } + + /* + * We start by assuming that all cells are visible, and then mark as + * invisible those that are outside the viewable area. + */ + for (int x = 0; x < columns.size(); x++) { + for (int y = 0; y < rows.size(); y++) { + Cell cell = rows.get(y).get(x); + cell.setVisible(true); + + // Special case: mouse double-clicks can lead to + // multiple cells in editing mode. Only allow a cell + // to remain editing if it is fact the active widget. + if (cell.isEditing && !cell.isActive()) { + cell.fieldText = cell.field.getText(); + cell.isEditing = false; + cell.field.setEnabled(false); + } + } + } + + // Adjust X locations to be visible ----------------------------------- + // Determine if we need to shift left or right. - int width = getMaximumWidth(); int leftCellX = 0; if (showRowLabels == true) { // For now, all row labels are 8 cells wide. TODO: make this // adjustable. - leftCellX += 8; + leftCellX += ROW_LABEL_WIDTH; } - // TODO + Row row = getSelectedRow(); + Cell selectedColumnCell = null; + for (int i = 0; i < row.cells.size(); i++) { + if (i == selectedColumn) { + selectedColumnCell = row.cells.get(i); + break; + } + leftCellX += row.cells.get(i).getWidth() + 1; + } + // There should always be a selected column. + assert (selectedColumnCell != null); + if (resetColumnX == true) { - // TODO: determine shift up/down + // We need to adjust everything so that the selected cell is + // visible. + int excessWidth = leftCellX + selectedColumnCell.getWidth() + 1 - getWidth(); + if (excessWidth > 0) { + leftCellX -= excessWidth; + } + if (leftCellX < 0) { + if (showRowLabels == true) { + leftCellX = ROW_LABEL_WIDTH; + } else { + leftCellX = 0; + } + } + /* + * leftCellX now contains the basic left offset necessary to draw + * the cells such that the selected cell (column) is fully + * visible within this widget's given width. Or, if the widget + * is too narrow to display the full cell, leftCellX is 0 or + * ROW_LABEL_WIDTH. + * + * Now reset all of the X positions of the other cells so that + * the selected cell X is leftCellX. + */ + for (int y = 0; y < rows.size(); y++) { + // All cells to the left of selected cell. + int newCellX = leftCellX; + left = selectedColumn - 1; + for (int x = selectedColumn - 1; x >= 0; x--) { + newCellX -= rows.get(y).get(x).getWidth() + 1; + rows.get(y).get(x).setX(newCellX); + if (newCellX >= (showRowLabels ? ROW_LABEL_WIDTH : 0)) { + if ((rows.get(y).get(0).getY() < (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)) + || (rows.get(y).get(0).getY() >= getHeight()) + ) { + // This row isn't visible. + rows.get(y).get(x).setVisible(false); + } else { + rows.get(y).get(x).setVisible(true); + } + left--; + } else { + // This cell won't be visible. + rows.get(y).get(x).setVisible(false); + } + } + left++; + + // Selected cell. + rows.get(y).get(selectedColumn).setX(leftCellX); + if ((rows.get(y).get(0).getY() < (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)) + || (rows.get(y).get(0).getY() >= getHeight()) + ) { + // This row isn't visible. + rows.get(y).get(selectedColumn).setVisible(false); + } else { + rows.get(y).get(selectedColumn).setVisible(true); + } + + assert (rows.get(y).get(left).getX() >= 0); + assert (rows.get(y).get(left).getX() + rows.get(y).get(left).getWidth() >= (showRowLabels ? ROW_LABEL_WIDTH : 0)); + + // All cells to the right of selected cell. + newCellX = leftCellX + selectedColumnCell.getWidth() + 1; + for (int x = selectedColumn + 1; x < columns.size(); x++) { + rows.get(y).get(x).setX(newCellX); + if (newCellX <= getWidth()) { + if ((rows.get(y).get(0).getY() < (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)) + || (rows.get(y).get(0).getY() >= getHeight()) + ) { + // This row isn't visible. + rows.get(y).get(x).setVisible(false); + } else { + rows.get(y).get(x).setVisible(true); + } + } else { + // This cell won't be visible. + rows.get(y).get(x).setVisible(false); + } + newCellX += rows.get(y).get(x).getWidth() + 1; + } + } + + } // if (resetColumnX == true) + + // Adjust Y locations to be visible ----------------------------------- + // The same logic as above, but applied to the column Y. + + // Determine if we need to shift up or down. + int topCellY = 0; + if (showColumnLabels == true) { + // For now, all column labels are 1 cell high. TODO: make this + // adjustable. + topCellY += 1; + } + Column column = getSelectedColumn(); + Cell selectedRowCell = null; + for (int i = 0; i < column.cells.size(); i++) { + if (i == selectedRow) { + selectedRowCell = column.cells.get(i); + break; + } + topCellY += column.cells.get(i).getHeight(); + // TODO: if a border is selected, add 1 to topCellY. + } + // There should always be a selected row. + assert (selectedRowCell != null); + + if (resetRowY == true) { + + // We need to adjust everything so that the selected cell is + // visible. + + int excessHeight = topCellY + selectedRowCell.getHeight() - getHeight() - 1; + if (showColumnLabels == true) { + excessHeight += COLUMN_LABEL_HEIGHT; + } + if (excessHeight > 0) { + topCellY -= excessHeight; + } + if (topCellY < 0) { + if (showColumnLabels == true) { + topCellY = COLUMN_LABEL_HEIGHT; + } else { + topCellY = 0; + } + } + + /* + * topCellY now contains the basic top offset necessary to draw + * the cells such that the selected cell (row) is fully visible + * within this widget's given height. Or, if the widget is too + * short to display the full cell, topCellY is 0 or + * COLUMN_LABEL_HEIGHT. + * + * Now reset all of the Y positions of the other cells so that + * the selected cell Y is topCellY. + */ + for (int x = 0; x < columns.size(); x++) { + // All cells above the selected cell. + int newCellY = topCellY; + top = selectedRow - 1; + for (int y = selectedRow - 1; y >= 0; y--) { + newCellY -= columns.get(x).get(y).getHeight(); + columns.get(x).get(y).setY(newCellY); + if (newCellY >= (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)) { + if ((columns.get(x).get(0).getX() < (showRowLabels ? ROW_LABEL_WIDTH : 0)) + || (columns.get(x).get(0).getX() >= getWidth()) + ) { + // This column isn't visible. + columns.get(x).get(y).setVisible(false); + } else { + columns.get(x).get(y).setVisible(true); + } + top--; + } else { + // This cell won't be visible. + columns.get(x).get(y).setVisible(false); + } + } + top++; + + // Selected cell. + columns.get(x).get(selectedRow).setY(topCellY); + if ((columns.get(x).get(0).getX() < (showRowLabels ? ROW_LABEL_WIDTH : 0)) + || (columns.get(x).get(0).getX() >= getWidth()) + ) { + // This column isn't visible. + columns.get(x).get(selectedRow).setVisible(false); + } else { + columns.get(x).get(selectedRow).setVisible(true); + } + + assert (columns.get(x).get(top).getY() >= 0); + assert (columns.get(x).get(top).getY() + columns.get(x).get(top).getHeight() >= (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)); + + // All cells below the selected cell. + newCellY = topCellY + selectedRowCell.getHeight(); + for (int y = selectedRow + 1; y < rows.size(); y++) { + columns.get(x).get(y).setY(newCellY); + if (newCellY <= getHeight()) { + if ((columns.get(x).get(0).getX() < (showRowLabels ? ROW_LABEL_WIDTH : 0)) + || (columns.get(x).get(0).getX() >= getWidth()) + ) { + // This column isn't visible. + columns.get(x).get(y).setVisible(false); + } else { + columns.get(x).get(y).setVisible(true); + } + } else { + // This cell won't be visible. + columns.get(x).get(y).setVisible(false); + } + newCellY += columns.get(x).get(y).getHeight(); + } + } + + } // if (resetRowY == true) + + } + + /** + * Save contents to file. + * + * @param filename file to save to + * @throws IOException if a java.io operation throws + */ + public void saveToFilename(final String filename) throws IOException { + // TODO } }