X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTableWidget.java;h=2a669dfb0edd2d80c2008283c66273040b22878e;hb=91b3175add6885fb93e69c72d009752c9925c99f;hp=bd53977341d93799f93d6fde43903a24712fb52c;hpb=77961919f5b88f024863cf33ffdfe8f3f9e98d83;p=fanfix.git diff --git a/src/jexer/TTableWidget.java b/src/jexer/TTableWidget.java index bd53977..2a669df 100644 --- a/src/jexer/TTableWidget.java +++ b/src/jexer/TTableWidget.java @@ -28,12 +28,14 @@ */ 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.*; @@ -78,6 +80,31 @@ 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; + + /** + * Column default width. + */ + private static final int COLUMN_DEFAULT_WIDTH = 8; + + /** + * 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 -------------------------------------------------------------- // ------------------------------------------------------------------------ @@ -115,12 +142,12 @@ 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. @@ -132,15 +159,30 @@ public class TTableWidget extends TWidget { */ 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. */ public class Column { + /** + * X position of this column. + */ + private int x = 0; + /** * Width of column. */ - private int width = 8; + private int width = COLUMN_DEFAULT_WIDTH; /** * The cells of this column. @@ -153,9 +195,9 @@ public class TTableWidget extends TWidget { 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. @@ -193,6 +235,28 @@ public class TTableWidget extends TWidget { public Cell get(final int row) { return cells.get(row); } + + /** + * Get the X position of the cells in this column. + * + * @return the position + */ + public int getX() { + return x; + } + + /** + * Set the X position of the cells in this column. + * + * @param x the position + */ + public void setX(final int x) { + for (Cell cell: cells) { + cell.setX(x); + } + this.x = x; + } + } /** @@ -200,6 +264,11 @@ public class TTableWidget extends TWidget { */ public class Row { + /** + * Y position of this row. + */ + private int y = 0; + /** * Height of row. */ @@ -216,9 +285,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. @@ -247,6 +316,26 @@ public class TTableWidget extends TWidget { public Cell get(final int column) { return cells.get(column); } + /** + * Get the Y position of the cells in this column. + * + * @return the position + */ + public int getY() { + return y; + } + + /** + * Set the Y position of the cells in this column. + * + * @param y the position + */ + public void setY(final int y) { + for (Cell cell: cells) { + cell.setY(y); + } + this.y = y; + } } @@ -318,6 +407,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(); + } + } + + /** + * 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(); + } + } + + /** + * 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(); + } + } + /** * Handle keystrokes. * @@ -442,25 +591,38 @@ 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) { - Cell cell = new Cell(this, j, i, columns.get(0).width, + for (int j = 0; j < width + EXTRA_COLUMNS; + j += columns.get(0).width) { + + Cell cell = new Cell(this, 0, 0, /* j, i, */ columns.get(0).width, rows.get(0).height, column, row); + // DEBUG: set a grid of cell index labels + // TODO: remove this 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++; } + for (int i = 0; i < rows.size(); i++) { + rows.get(i).setY(i + (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0)); + } + for (int j = 0; j < columns.size(); j++) { + columns.get(j).setX((j * COLUMN_DEFAULT_WIDTH) + + (showRowLabels ? ROW_LABEL_WIDTH : 0)); + } activate(columns.get(selectedColumn).get(selectedRow)); alignGrid(); @@ -482,6 +644,31 @@ public class TTableWidget extends TWidget { // 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. * @@ -504,39 +691,65 @@ public class TTableWidget extends TWidget { } 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)); } else if (keypress.equals(kbEnd)) { + // End - rightmost column selectedColumn = columns.size() - 1; activate(columns.get(selectedColumn).get(selectedRow)); } 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)); } 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)); } 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)); } 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)); } else { // Pass to the Cell. super.onKeypress(keypress); @@ -580,13 +793,57 @@ public class TTableWidget extends TWidget { highlightColumn = getApplication().getMenuItem(menu.getId()).getChecked(); break; case TMenu.MID_TABLE_BORDER_NONE: + if (selectedRow == 0) { + topBorder = Border.NONE; + } + if (selectedColumn == 0) { + leftBorder = Border.NONE; + } + columns.get(selectedColumn).rightBorder = Border.NONE; + rows.get(selectedRow).bottomBorder = Border.NONE; + rows.get(selectedRow).height = 1; + break; case TMenu.MID_TABLE_BORDER_ALL: + if (selectedRow == 0) { + topBorder = Border.SINGLE; + } + if (selectedColumn == 0) { + leftBorder = Border.SINGLE; + } + columns.get(selectedColumn).rightBorder = Border.SINGLE; + rows.get(selectedRow).bottomBorder = Border.SINGLE; + rows.get(selectedRow).height = 2; + break; case TMenu.MID_TABLE_BORDER_RIGHT: + columns.get(selectedColumn).rightBorder = Border.SINGLE; + break; case TMenu.MID_TABLE_BORDER_LEFT: + if (selectedColumn == 0) { + leftBorder = Border.SINGLE; + } else { + columns.get(selectedColumn - 1).rightBorder = Border.SINGLE; + } + break; case TMenu.MID_TABLE_BORDER_TOP: + if (selectedRow == 0) { + topBorder = Border.SINGLE; + } else { + rows.get(selectedRow - 1).bottomBorder = Border.SINGLE; + rows.get(selectedRow - 1).height = 2; + } + break; case TMenu.MID_TABLE_BORDER_BOTTOM: + rows.get(selectedRow).bottomBorder = Border.SINGLE; + rows.get(selectedRow).height = 2; + break; case TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM: + rows.get(selectedRow).bottomBorder = Border.DOUBLE; + rows.get(selectedRow).height = 2; + break; case TMenu.MID_TABLE_BORDER_THICK_BOTTOM: + rows.get(selectedRow).bottomBorder = Border.THICK; + rows.get(selectedRow).height = 2; + break; case TMenu.MID_TABLE_DELETE_LEFT: case TMenu.MID_TABLE_DELETE_UP: case TMenu.MID_TABLE_DELETE_ROW: @@ -600,35 +857,33 @@ 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); - } + columns.get(i).setX(columns.get(i).getX() - 1); } - alignGrid(); 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); - } + columns.get(i).setX(columns.get(i).getX() + 1); } - alignGrid(); break; case TMenu.MID_TABLE_FILE_SAVE_CSV: + // TODO + break; case TMenu.MID_TABLE_FILE_SAVE_TEXT: + // TODO break; default: super.onMenu(menu); } + // Fix/redraw the display. alignGrid(); } @@ -651,8 +906,11 @@ public class TTableWidget extends TWidget { if (columns.get(i).get(top).isVisible() == false) { break; } - putStringXY(columns.get(i).get(top).getX(), 0, - String.format(" %-6s ", columns.get(i).label), + putStringXY(columns.get(i).get(top).getX(), + (topBorder == Border.NONE ? 0 : 1), + String.format(" %-" + + (columns.get(i).width - 2) + + "s ", columns.get(i).label), (i == selectedColumn ? labelColorSelected : labelColor)); } } @@ -669,6 +927,56 @@ public class TTableWidget extends TWidget { } } + // Draw vertical borders. + if (leftBorder == Border.SINGLE) { + vLineXY((showRowLabels ? ROW_LABEL_WIDTH : 0), 0, + getHeight(), '\u2502', borderColor); + } + for (int i = left; i < columns.size(); i++) { + if (columns.get(i).get(top).isVisible() == false) { + break; + } + if (columns.get(i).rightBorder == Border.SINGLE) { + vLineXY(columns.get(i).getX() + columns.get(i).width, + (topBorder == Border.NONE ? 0 : 1), + getHeight(), '\u2502', borderColor); + } + } + + // Draw horizontal borders. + if (topBorder == Border.SINGLE) { + hLineXY((showRowLabels ? ROW_LABEL_WIDTH : 0), 0, + getWidth(), '\u2500', borderColor); + } + for (int i = top; i < rows.size(); i++) { + if (rows.get(i).get(left).isVisible() == false) { + break; + } + if (rows.get(i).bottomBorder == Border.SINGLE) { + hLineXY((leftBorder == Border.NONE ? 0 : 1) + + (showRowLabels ? ROW_LABEL_WIDTH : 0), + rows.get(i).getY() + rows.get(i).height - 1, + getWidth(), '\u2500', borderColor); + } else if (rows.get(i).bottomBorder == Border.DOUBLE) { + hLineXY((leftBorder == Border.NONE ? 0 : 1) + + (showRowLabels ? ROW_LABEL_WIDTH : 0), + rows.get(i).getY() + rows.get(i).height - 1, + getWidth(), '\u2550', borderColor); + } else if (rows.get(i).bottomBorder == Border.THICK) { + hLineXY((leftBorder == Border.NONE ? 0 : 1) + + (showRowLabels ? ROW_LABEL_WIDTH : 0), + rows.get(i).getY() + rows.get(i).height - 1, + getWidth(), '\u2580', borderColor); + } + } + // Top-left corner if needed + if ((topBorder == Border.SINGLE) && (leftBorder == Border.SINGLE)) { + putCharXY((showRowLabels ? ROW_LABEL_WIDTH : 0), 0, + '\u250c', borderColor); + } + + // TODO: draw the correct corners between rows and columns + // Now draw the window borders. super.draw(); } @@ -718,220 +1026,238 @@ 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; - } - for (Cell cell: getSelectedRow().cells) { - totalWidth += cell.getWidth() + 1; - } - return totalWidth; + public int getSelectedColumnNumber() { + return selectedColumn; } /** - * Get the full vertical height of this table. + * Set the currently-selected column number. 0 is the left-most column. * - * @return the height required to render the entire table + * @param column the column number to select */ - public int getMaximumHeight() { - int totalHeight = 0; - if (showColumnLabels == true) { - // For now, all column labels are 1 cell tall. TODO: make this - // adjustable. - totalHeight += 1; - } - for (Cell cell: getSelectedColumn().cells) { - totalHeight += cell.getHeight(); - // TODO: handle top/bottom borders. + public void setSelectedColumnNumber(final int column) { + if ((column < 0) || (column > columns.size() - 1)) { + throw new IndexOutOfBoundsException("Column count is " + + columns.size() + ", requested index " + column); } - return totalHeight; + selectedColumn = column; + activate(columns.get(selectedColumn).get(selectedRow)); + alignGrid(); } /** - * Align the grid so that the selected cell is fully visible. + * Get the currently-selected row number. 0 is the top-most row. + * + * @return the selected row number */ - private void alignGrid() { + public int getSelectedRowNumber() { + return selectedRow; + } - /* - * 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++) { - rows.get(y).cells.get(x).setVisible(true); - } + /** + * 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); } + selectedRow = row; + activate(columns.get(selectedColumn).get(selectedRow)); + alignGrid(); + } + + /** + * Get the number of columns. + * + * @return the number of columns + */ + public int getColumnCount() { + return columns.size(); + } - // Adjust X locations to be visible ----------------------------------- + /** + * Get the number of rows. + * + * @return the number of rows + */ + public int getRowCount() { + return rows.size(); + } - // Determine if we need to shift left or right. - int leftCellX = 0; + /** + * Align the grid so that the selected cell is fully visible. + */ + private void alignGrid() { + int viewColumns = getWidth(); if (showRowLabels == true) { - // For now, all row labels are 8 cells wide. TODO: make this - // adjustable. - leftCellX += 8; - } - 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; + viewColumns -= ROW_LABEL_WIDTH; + } + if (leftBorder != Border.NONE) { + viewColumns--; + } + int viewRows = getHeight(); + if (showColumnLabels == true) { + viewRows -= COLUMN_LABEL_HEIGHT; + } + if (topBorder != Border.NONE) { + viewRows--; } - // There should always be a selected column. - assert (selectedColumnCell != null); - int excessWidth = leftCellX + selectedColumnCell.getWidth() + 1 - getWidth(); - if (excessWidth > 0) { - leftCellX -= excessWidth; + // If we pushed left or right, adjust the box to include the new + // selected cell. + if (selectedColumn < left) { + left = selectedColumn - 1; } - if (leftCellX < 0) { - if (showRowLabels == true) { - leftCellX = 8; - } else { - leftCellX = 0; - } + if (left < 0) { + left = 0; + } + if (selectedRow < top) { + top = selectedRow - 1; + } + if (top < 0) { + top = 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 8. + * viewColumns and viewRows now contain the available columns and + * rows available to view the selected cell. We adjust left and top + * to ensure the selected cell is within view, and then make all + * cells outside the box between (left, top) and (right, bottom) + * invisible. * - * Now reset all of the X positions of the other cells so that the - * selected cell X is leftCellX. + * We need to calculate right and bottom now. */ - for (int y = 0; y < rows.size(); y++) { - // All cells to the left of selected cell. - int newCellX = leftCellX; - left = selectedColumn; - for (int x = selectedColumn - 1; x >= 0; x--) { - newCellX -= rows.get(y).cells.get(x).getWidth() + 1; - if (newCellX - rows.get(y).cells.get(x).getWidth() + 1 >= 0) { - rows.get(y).cells.get(x).setVisible(true); - rows.get(y).cells.get(x).setX(newCellX); - left--; - } else { - // This cell won't be visible. - rows.get(y).cells.get(x).setVisible(false); - } - } - - // Selected cell. - rows.get(y).cells.get(selectedColumn).setX(leftCellX); - assert (rows.get(y).cells.get(selectedColumn).isVisible()); + int right = left; - // All cells to the right of selected cell. - newCellX = leftCellX + selectedColumnCell.getWidth() + 1; - for (int x = selectedColumn + 1; x < columns.size(); x++) { - if (newCellX <= getWidth()) { - rows.get(y).cells.get(x).setVisible(true); - rows.get(y).cells.get(x).setX(newCellX); - } else { - // This cell won't be visible. - rows.get(y).cells.get(x).setVisible(false); + boolean done = false; + while (!done) { + int rightCellX = (showRowLabels ? ROW_LABEL_WIDTH : 0); + if (leftBorder != Border.NONE) { + rightCellX++; + } + int maxCellX = rightCellX + viewColumns; + right = left; + boolean selectedIsVisible = false; + int selectedX = 0; + for (int x = left; x < columns.size(); x++) { + if (x == selectedColumn) { + selectedX = rightCellX; + if (selectedX + columns.get(x).width + 1 <= maxCellX) { + selectedIsVisible = true; + } } - newCellX += rows.get(y).cells.get(x).getWidth() + 1; + rightCellX += columns.get(x).width + 1; + if (rightCellX >= maxCellX) { + break; + } + right++; } - } - - // 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; + if (right < selectedColumn) { + // selectedColumn is outside the view range. Push left over, + // and calculate again. + left++; + } else if (left == selectedColumn) { + // selectedColumn doesn't fit inside the view range, but we + // can't go over any further either. Bail out. + done = true; + } else if (selectedIsVisible == false) { + // selectedColumn doesn't fit inside the view range, continue + // on. + left++; + } else { + // selectedColumn is fully visible, all done. + assert (selectedIsVisible == true); + done = true; } - 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); - int excessHeight = topCellY + selectedRowCell.getHeight() - getHeight() - 1; - if (showColumnLabels == true) { - excessHeight += 1; - } - if (excessHeight > 0) { - topCellY -= excessHeight; + } // while (!done) + + // We have the left/right range correct, set cell visibility and + // column X positions. + int leftCellX = showRowLabels ? ROW_LABEL_WIDTH : 0; + if (leftBorder != Border.NONE) { + leftCellX++; } - if (topCellY < 0) { - if (showColumnLabels == true) { - topCellY = 1; - } else { - topCellY = 0; + for (int x = 0; x < columns.size(); x++) { + if ((x < left) || (x > right)) { + for (int i = 0; i < rows.size(); i++) { + columns.get(x).get(i).setVisible(false); + columns.get(x).setX(getWidth() + 1); + } + continue; + } + for (int i = 0; i < rows.size(); i++) { + columns.get(x).get(i).setVisible(true); } + columns.get(x).setX(leftCellX); + leftCellX += columns.get(x).width + 1; } - /* - * 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 1. - * - * 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++) { + int bottom = top; - if (columns.get(x).get(0).isVisible() == false) { - // This column won't be visible as determined by the checks - // above, just continue to the next. - continue; + done = false; + while (!done) { + int bottomCellY = (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0); + if (topBorder != Border.NONE) { + bottomCellY++; } - - // All cells above the selected cell. - int newCellY = topCellY; - top = selectedRow; - for (int y = selectedRow - 1; y >= 0; y--) { - newCellY -= rows.get(y).cells.get(x).getHeight(); - if (newCellY >= (showColumnLabels == true ? 1 : 0)) { - rows.get(y).cells.get(x).setVisible(true); - rows.get(y).cells.get(x).setY(newCellY); - top--; - } else { - // This cell won't be visible. - rows.get(y).cells.get(x).setVisible(false); + int maxCellY = bottomCellY + viewRows; + bottom = top; + for (int y = top; y < rows.size(); y++) { + bottomCellY += rows.get(y).height; + if (bottomCellY >= maxCellY) { + break; } + bottom++; } + if (bottom < selectedRow) { + // selectedRow is outside the view range. Push top down, and + // calculate again. + top++; + } else { + // selectedRow is inside the view range, done. + done = true; + } + } // while (!done) - // Selected cell. - columns.get(x).cells.get(selectedRow).setY(topCellY); - - // All cells below the selected cell. - newCellY = topCellY + selectedRowCell.getHeight(); - for (int y = selectedRow + 1; y < rows.size(); y++) { - if (newCellY <= getHeight()) { - rows.get(y).cells.get(x).setVisible(true); - rows.get(y).cells.get(x).setY(newCellY); - } else { - // This cell won't be visible. - rows.get(y).cells.get(x).setVisible(false); + // We have the top/bottom range correct, set cell visibility and + // row Y positions. + int topCellY = showColumnLabels ? COLUMN_LABEL_HEIGHT : 0; + if (topBorder != Border.NONE) { + topCellY++; + } + for (int y = 0; y < rows.size(); y++) { + if ((y < top) || (y > bottom)) { + for (int i = 0; i < columns.size(); i++) { + rows.get(y).get(i).setVisible(false); } - newCellY += rows.get(y).cells.get(x).getHeight(); + rows.get(y).setY(getHeight() + 1); + continue; + } + for (int i = 0; i < columns.size(); i++) { + rows.get(y).get(i).setVisible(true); } + rows.get(y).setY(topCellY); + topCellY += rows.get(y).height; } } + /** + * 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 + } + }