X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTableWidget.java;fp=src%2Fjexer%2FTTableWidget.java;h=0000000000000000000000000000000000000000;hb=36b0745bab5665306391440a531e1ee1c0625445;hp=9b4d7c9847faaa6688dae4a65b63173169683e77;hpb=686d4da2d2ecc203d5f8b524225a4327777825be;p=fanfix.git diff --git a/src/jexer/TTableWidget.java b/src/jexer/TTableWidget.java deleted file mode 100644 index 9b4d7c9..0000000 --- a/src/jexer/TTableWidget.java +++ /dev/null @@ -1,2361 +0,0 @@ -/* - * Jexer - Java Text User Interface - * - * The MIT License (MIT) - * - * Copyright (C) 2019 Kevin Lamonte - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * @author Kevin Lamonte [kevin.lamonte@gmail.com] - * @version 1 - */ -package jexer; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import jexer.bits.CellAttributes; -import jexer.bits.StringUtils; -import jexer.event.TKeypressEvent; -import jexer.event.TMouseEvent; -import jexer.event.TResizeEvent; -import static jexer.TKeypress.*; - -/** - * TTableWidget is used to display and edit regular two-dimensional tables of - * cells. - * - * This class was inspired by a TTable implementation originally developed by - * David "Niki" ROULET [niki@nikiroo.be], made available under MIT at - * https://github.com/nikiroo/jexer/tree/ttable_pull. - */ -public class TTableWidget extends TWidget { - - // ------------------------------------------------------------------------ - // Constants -------------------------------------------------------------- - // ------------------------------------------------------------------------ - - /** - * Available borders for cells. - */ - public enum Border { - /** - * No border. - */ - NONE, - - /** - * Single bar: \u2502 (vertical) and \u2500 (horizontal). - */ - SINGLE, - - /** - * Double bar: \u2551 (vertical) and \u2550 (horizontal). - */ - DOUBLE, - - /** - * Thick bar: \u2503 (vertical heavy) and \u2501 (horizontal heavy). - */ - THICK, - } - - /** - * If true, put a grid of numbers in the cells. - */ - private static final boolean DEBUG = false; - - /** - * 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 = (DEBUG ? 10 : 0); - - /** - * Extra columns to add. - */ - private static final int EXTRA_COLUMNS = (DEBUG ? 3 : 0); - - // ------------------------------------------------------------------------ - // Variables -------------------------------------------------------------- - // ------------------------------------------------------------------------ - - /** - * The underlying data, organized as columns. - */ - private ArrayList columns = new ArrayList(); - - /** - * The underlying data, organized as rows. - */ - private ArrayList rows = new ArrayList(); - - /** - * The row in model corresponding to the top-left visible cell. - */ - private int top = 0; - - /** - * The column in model corresponding to the top-left visible cell. - */ - private int left = 0; - - /** - * The row in model corresponding to the currently selected cell. - */ - private int selectedRow = 0; - - /** - * The column in model corresponding to the currently selected cell. - */ - private int selectedColumn = 0; - - /** - * If true, highlight the entire row of the currently-selected cell. - */ - private boolean highlightRow = false; - - /** - * If true, highlight the entire column of the currently-selected cell. - */ - 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. - */ - public class Column { - - /** - * X position of this column. - */ - private int x = 0; - - /** - * Width of column. - */ - private int width = COLUMN_DEFAULT_WIDTH; - - /** - * The cells of this column. - */ - private ArrayList cells = new ArrayList(); - - /** - * Column label. - */ - private String label = ""; - - /** - * The right border for this column. - */ - private Border rightBorder = Border.NONE; - - /** - * Constructor sets label to lettered column. - * - * @param col column number to use for this column. Column 0 will be - * "A", column 1 will be "B", column 26 will be "AA", and so on. - */ - Column(int col) { - label = makeColumnLabel(col); - } - - /** - * Add an entry to this column. - * - * @param cell the cell to add - */ - public void add(final Cell cell) { - cells.add(cell); - } - - /** - * Get an entry from this column. - * - * @param row the entry index to get - * @return the cell at row - */ - 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; - } - - } - - /** - * Row represents a row of cells. - */ - public class Row { - - /** - * Y position of this row. - */ - private int y = 0; - - /** - * Height of row. - */ - private int height = 1; - - /** - * The cells of this row. - */ - private ArrayList cells = new ArrayList(); - - /** - * Row label. - */ - private String label = ""; - - /** - * The bottom border for this row. - */ - private Border bottomBorder = Border.NONE; - - /** - * Constructor sets label to numbered row. - * - * @param row row number to use for this row - */ - Row(final int row) { - label = Integer.toString(row); - } - - /** - * Add an entry to this column. - * - * @param cell the cell to add - */ - public void add(final Cell cell) { - cells.add(cell); - } - - /** - * Get an entry from this row. - * - * @param column the entry index to get - * @return the cell at column - */ - 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; - } - - } - - /** - * Cell represents an editable cell in the table. Normally, navigation - * to a cell only highlights it; pressing Enter or F2 will switch to - * editing mode. - */ - public class Cell extends TWidget { - - // -------------------------------------------------------------------- - // Variables ---------------------------------------------------------- - // -------------------------------------------------------------------- - - /** - * The field containing the cell's data. - */ - private TField field; - - /** - * The column of this cell. - */ - private int column; - - /** - * The row of this cell. - */ - private int row; - - /** - * If true, the cell is being edited. - */ - private boolean isEditing = false; - - /** - * If true, the cell is read-only (non-editable). - */ - private boolean readOnly = false; - - /** - * Text of field before editing. - */ - private String fieldText; - - // -------------------------------------------------------------------- - // Constructors ------------------------------------------------------- - // -------------------------------------------------------------------- - - /** - * Public constructor. - * - * @param parent parent widget - * @param x column relative to parent - * @param y row relative to parent - * @param width width of widget - * @param height height of widget - * @param column column index of this cell - * @param row row index of this cell - */ - public Cell(final TTableWidget parent, final int x, final int y, - final int width, final int height, final int column, - final int row) { - - super(parent, x, y, width, height); - this.column = column; - this.row = row; - - field = addField(0, 0, width, false); - field.setEnabled(false); - field.setBackgroundChar(' '); - } - - // -------------------------------------------------------------------- - // 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. - * - * @param keypress keystroke event - */ - @Override - public void onKeypress(final TKeypressEvent keypress) { - // System.err.println("Cell onKeypress: " + keypress); - - if (readOnly) { - // Read only: do nothing. - return; - } - - if (isEditing) { - if (keypress.equals(kbEsc)) { - // ESC cancels the edit. - cancelEdit(); - return; - } - if (keypress.equals(kbEnter)) { - // Enter ends editing. - - // Pass down to field first so that it can execute - // enterAction if specified. - super.onKeypress(keypress); - - fieldText = field.getText(); - isEditing = false; - field.setEnabled(false); - return; - } - // Pass down to field. - super.onKeypress(keypress); - } - - if (keypress.equals(kbEnter) || keypress.equals(kbF2)) { - // Enter or F2 starts editing. - fieldText = field.getText(); - isEditing = true; - field.setEnabled(true); - activate(field); - return; - } - } - - // -------------------------------------------------------------------- - // TWidget ------------------------------------------------------------ - // -------------------------------------------------------------------- - - /** - * Draw this cell. - */ - @Override - public void draw() { - TTableWidget table = (TTableWidget) getParent(); - - if (isAbsoluteActive()) { - if (isEditing) { - field.setActiveColorKey("tfield.active"); - field.setInactiveColorKey("tfield.inactive"); - } else { - field.setActiveColorKey("ttable.selected"); - field.setInactiveColorKey("ttable.selected"); - } - } else if (((table.selectedColumn == column) - && ((table.selectedRow == row) - || (table.highlightColumn == true))) - || ((table.selectedRow == row) - && ((table.selectedColumn == column) - || (table.highlightRow == true))) - ) { - field.setActiveColorKey("ttable.active"); - field.setInactiveColorKey("ttable.active"); - } else { - field.setActiveColorKey("ttable.active"); - field.setInactiveColorKey("ttable.inactive"); - } - - assert (isVisible() == true); - - super.draw(); - } - - // -------------------------------------------------------------------- - // TTable.Cell -------------------------------------------------------- - // -------------------------------------------------------------------- - - /** - * Get field text. - * - * @return field text - */ - public final String getText() { - return field.getText(); - } - - /** - * Set field text. - * - * @param text the new field text - */ - public void setText(final String text) { - field.setText(text); - } - - /** - * Cancel any pending edit. - */ - public void cancelEdit() { - // Cancel any pending edit. - if (fieldText != null) { - field.setText(fieldText); - } - isEditing = false; - field.setEnabled(false); - } - - /** - * Set an entire column of cells read-only (non-editable) or not. - * - * @param readOnly if true, the cells will be non-editable - */ - public void setReadOnly(final boolean readOnly) { - cancelEdit(); - this.readOnly = readOnly; - } - - } - - // ------------------------------------------------------------------------ - // Constructors ----------------------------------------------------------- - // ------------------------------------------------------------------------ - - /** - * Public constructor. - * - * @param parent parent widget - * @param x column relative to parent - * @param y row relative to parent - * @param width width of widget - * @param height height of widget - * @param gridColumns number of columns in grid - * @param gridRows number of rows in grid - */ - public TTableWidget(final TWidget parent, final int x, final int y, - final int width, final int height, final int gridColumns, - final int gridRows) { - - super(parent, x, y, width, height); - - /* - System.err.println("gridColumns " + gridColumns + - " gridRows " + gridRows); - */ - - if (gridColumns < 1) { - throw new IllegalArgumentException("Column count cannot be less " + - "than 1"); - } - if (gridRows < 1) { - throw new IllegalArgumentException("Row count cannot be less " + - "than 1"); - } - - // Initialize the starting row and column. - rows.add(new Row(0)); - columns.add(new Column(0)); - assert (rows.get(0).height == 1); - - // Place a grid of cells that fit in this space. - for (int row = 0; row < gridRows; row++) { - for (int column = 0; column < gridColumns; column++) { - Cell cell = new Cell(this, 0, 0, COLUMN_DEFAULT_WIDTH, 1, - column, row); - - if (DEBUG) { - // For debugging: set a grid of cell index labels. - cell.setText("" + row + " " + column); - } - rows.get(row).add(cell); - columns.get(column).add(cell); - - if (columns.size() < gridColumns) { - columns.add(new Column(column + 1)); - } - } - if (row < gridRows - 1) { - rows.add(new Row(row + 1)); - } - } - 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 + 1)) + - (showRowLabels ? ROW_LABEL_WIDTH : 0)); - } - activate(columns.get(selectedColumn).get(selectedRow)); - - alignGrid(); - } - - /** - * Public constructor. - * - * @param parent parent widget - * @param x column relative to parent - * @param y row relative to parent - * @param width width of widget - * @param height height of widget - */ - public TTableWidget(final TWidget parent, final int x, final int y, - final int width, final int height) { - - this(parent, x, y, width, height, - width / (COLUMN_DEFAULT_WIDTH + 1) + EXTRA_COLUMNS, - height + EXTRA_ROWS); - } - - // ------------------------------------------------------------------------ - // 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. - * - * @param keypress keystroke event - */ - @Override - public void onKeypress(final TKeypressEvent keypress) { - if (keypress.equals(kbTab) - || keypress.equals(kbShiftTab) - ) { - // Squash tab and back-tab. They don't make sense in the TTable - // grid context. - return; - } - - // If editing, pass to that cell and do nothing else. - if (getSelectedCell().isEditing) { - super.onKeypress(keypress); - return; - } - - 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)) { - // 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)) { - // 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)) { - // 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)) { - // 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); - } - - // We may have scrolled off screen. Reset positions as needed to - // make the newly selected cell visible. - alignGrid(); - } - - /** - * Handle widget resize events. - * - * @param event resize event - */ - @Override - public void onResize(final TResizeEvent event) { - super.onResize(event); - - bottomRightCorner(); - } - - // ------------------------------------------------------------------------ - // 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)); - } - } - - // Draw vertical borders. - if (leftBorder == Border.SINGLE) { - vLineXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - (topBorder == Border.NONE ? 0 : 1) + - (showColumnLabels ? COLUMN_LABEL_HEIGHT : 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) + - (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0), - getHeight(), '\u2502', borderColor); - } - } - - // Draw horizontal borders. - if (topBorder == Border.SINGLE) { - hLineXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - (showColumnLabels ? COLUMN_LABEL_HEIGHT : 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(), '\u2501', borderColor); - } - } - // Top-left corner if needed - if ((topBorder == Border.SINGLE) && (leftBorder == Border.SINGLE)) { - putCharXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0), - '\u250c', borderColor); - } - - // Now draw the correct corners - for (int i = top; i < rows.size(); i++) { - if (rows.get(i).get(left).isVisible() == false) { - break; - } - for (int j = left; j < columns.size(); j++) { - if (columns.get(j).get(i).isVisible() == false) { - break; - } - if ((i == top) && (topBorder == Border.SINGLE) - && (columns.get(j).rightBorder == Border.SINGLE) - ) { - // Top tee - putCharXY(columns.get(j).getX() + columns.get(j).width, - (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0), - '\u252c', borderColor); - } - if ((j == left) && (leftBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.SINGLE) - ) { - // Left tee - putCharXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - rows.get(i).getY() + rows.get(i).height - 1, - '\u251c', borderColor); - } - if ((columns.get(j).rightBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.SINGLE) - ) { - // Intersection of single bars - putCharXY(columns.get(j).getX() + columns.get(j).width, - rows.get(i).getY() + rows.get(i).height - 1, - '\u253c', borderColor); - } - if ((j == left) && (leftBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.DOUBLE) - ) { - // Left tee: single bar vertical, double bar horizontal - putCharXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - rows.get(i).getY() + rows.get(i).height - 1, - '\u255e', borderColor); - } - if ((j == left) && (leftBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.THICK) - ) { - // Left tee: single bar vertical, thick bar horizontal - putCharXY((showRowLabels ? ROW_LABEL_WIDTH : 0), - rows.get(i).getY() + rows.get(i).height - 1, - '\u251d', borderColor); - } - if ((columns.get(j).rightBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.DOUBLE) - ) { - // Intersection: single bar vertical, double bar - // horizontal - putCharXY(columns.get(j).getX() + columns.get(j).width, - rows.get(i).getY() + rows.get(i).height - 1, - '\u256a', borderColor); - } - if ((columns.get(j).rightBorder == Border.SINGLE) - && (rows.get(i).bottomBorder == Border.THICK) - ) { - // Intersection: single bar vertical, thick bar - // horizontal - putCharXY(columns.get(j).getX() + columns.get(j).width, - rows.get(i).getY() + rows.get(i).height - 1, - '\u253f', borderColor); - } - } - } - - // Now draw the window borders. - super.draw(); - } - - // ------------------------------------------------------------------------ - // TTable ----------------------------------------------------------------- - // ------------------------------------------------------------------------ - - /** - * Generate the default letter name for a column number. - * - * @param col column number to use for this column. Column 0 will be - * "A", column 1 will be "B", column 26 will be "AA", and so on. - */ - private String makeColumnLabel(int col) { - StringBuilder sb = new StringBuilder(); - for (;;) { - sb.append((char) ('A' + (col % 26))); - if (col < 26) { - break; - } - col /= 26; - } - return sb.reverse().toString(); - } - - /** - * Get the currently-selected cell. - * - * @return the selected cell - */ - public Cell getSelectedCell() { - assert (rows.get(selectedRow) != null); - assert (rows.get(selectedRow).get(selectedColumn) != null); - assert (columns.get(selectedColumn) != null); - assert (columns.get(selectedColumn).get(selectedRow) != null); - assert (rows.get(selectedRow).get(selectedColumn) == - columns.get(selectedColumn).get(selectedRow)); - - return (columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Get the currently-selected column. - * - * @return the selected column - */ - public Column getSelectedColumn() { - assert (selectedColumn >= 0); - assert (columns.size() > selectedColumn); - assert (columns.get(selectedColumn) != null); - return columns.get(selectedColumn); - } - - /** - * Get the currently-selected row. - * - * @return the selected row - */ - public Row getSelectedRow() { - assert (selectedRow >= 0); - assert (rows.size() > selectedRow); - assert (rows.get(selectedRow) != null); - return rows.get(selectedRow); - } - - /** - * Get the currently-selected column number. 0 is the left-most column. - * - * @return the selected column number - */ - 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); - } - selectedColumn = column; - activate(columns.get(selectedColumn).get(selectedRow)); - alignGrid(); - } - - /** - * 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); - } - selectedRow = row; - activate(columns.get(selectedColumn).get(selectedRow)); - alignGrid(); - } - - /** - * Get the highlight row flag. - * - * @return true if the selected row is highlighted - */ - public boolean getHighlightRow() { - return highlightRow; - } - - /** - * Set the highlight row flag. - * - * @param highlightRow if true, the selected row will be highlighted - */ - public void setHighlightRow(final boolean highlightRow) { - this.highlightRow = highlightRow; - } - - /** - * Get the highlight column flag. - * - * @return true if the selected column is highlighted - */ - public boolean getHighlightColumn() { - return highlightColumn; - } - - /** - * Set the highlight column flag. - * - * @param highlightColumn if true, the selected column will be highlighted - */ - public void setHighlightColumn(final boolean highlightColumn) { - this.highlightColumn = highlightColumn; - } - - /** - * Get the show row labels flag. - * - * @return true if row labels are shown - */ - public boolean getShowRowLabels() { - return showRowLabels; - } - - /** - * Set the show row labels flag. - * - * @param showRowLabels if true, the row labels will be shown - */ - public void setShowRowLabels(final boolean showRowLabels) { - this.showRowLabels = showRowLabels; - } - - /** - * Get the show column labels flag. - * - * @return true if column labels are shown - */ - public boolean getShowColumnLabels() { - return showColumnLabels; - } - - /** - * Set the show column labels flag. - * - * @param showColumnLabels if true, the column labels will be shown - */ - public void setShowColumnLabels(final boolean showColumnLabels) { - this.showColumnLabels = showColumnLabels; - } - - /** - * 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(); - } - - - /** - * Push top and left to the bottom-most right corner of the available - * grid. - */ - private void bottomRightCorner() { - int viewColumns = getWidth(); - if (showRowLabels == true) { - viewColumns -= ROW_LABEL_WIDTH; - } - - // Set left and top such that the table stays on screen if possible. - top = rows.size() - getHeight(); - left = columns.size() - (getWidth() / (viewColumns / (COLUMN_DEFAULT_WIDTH + 1))); - // Now ensure the selection is visible. - alignGrid(); - } - - /** - * Align the grid so that the selected cell is fully visible. - */ - private void alignGrid() { - - /* - System.err.println("alignGrid() # columns " + columns.size() + - " # rows " + rows.size()); - */ - - int viewColumns = getWidth(); - if (showRowLabels == true) { - viewColumns -= ROW_LABEL_WIDTH; - } - if (leftBorder != Border.NONE) { - viewColumns--; - } - int viewRows = getHeight(); - if (showColumnLabels == true) { - viewRows -= COLUMN_LABEL_HEIGHT; - } - if (topBorder != Border.NONE) { - viewRows--; - } - - // If we pushed left or right, adjust the box to include the new - // selected cell. - if (selectedColumn < left) { - left = selectedColumn - 1; - } - if (left < 0) { - left = 0; - } - if (selectedRow < top) { - top = selectedRow - 1; - } - if (top < 0) { - top = 0; - } - - /* - * 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. - * - * We need to calculate right and bottom now. - */ - int right = left; - - 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; - } - } - rightCellX += columns.get(x).width + 1; - if (rightCellX >= maxCellX) { - break; - } - right++; - } - 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; - } - - } // 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++; - } - 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; - } - - int bottom = top; - - done = false; - while (!done) { - int bottomCellY = (showColumnLabels ? COLUMN_LABEL_HEIGHT : 0); - if (topBorder != Border.NONE) { - bottomCellY++; - } - 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) - - // 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); - } - 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; - } - - // Last thing: cancel any edits that are not the selected cell. - for (int y = 0; y < rows.size(); y++) { - for (int x = 0; x < columns.size(); x++) { - if ((x == selectedColumn) && (y == selectedRow)) { - continue; - } - rows.get(y).get(x).cancelEdit(); - } - } - } - - /** - * Load contents from file in CSV format. - * - * @param csvFile a File referencing the CSV data - * @throws IOException if a java.io operation throws - */ - public void loadCsvFile(final File csvFile) throws IOException { - BufferedReader reader = null; - - try { - reader = new BufferedReader(new FileReader(csvFile)); - - String line = null; - boolean first = true; - for (line = reader.readLine(); line != null; - line = reader.readLine()) { - - List list = StringUtils.fromCsv(line); - if (list.size() == 0) { - continue; - } - - if (list.size() > columns.size()) { - int n = list.size() - columns.size(); - for (int i = 0; i < n; i++) { - selectedColumn = columns.size() - 1; - insertColumnRight(selectedColumn); - } - } - assert (list.size() == columns.size()); - - if (first) { - // First row: just replace what is here. - selectedRow = 0; - first = false; - } else { - // All other rows: append to the end. - selectedRow = rows.size() - 1; - insertRowBelow(selectedRow); - selectedRow = rows.size() - 1; - } - for (int i = 0; i < list.size(); i++) { - rows.get(selectedRow).get(i).setText(list.get(i)); - } - - // TODO: detect header line - } - } finally { - if (reader != null) { - reader.close(); - } - } - - left = 0; - top = 0; - selectedRow = 0; - selectedColumn = 0; - alignGrid(); - activate(columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Save contents to file in CSV format. - * - * @param filename file to save to - * @throws IOException if a java.io operation throws - */ - public void saveToCsvFilename(final String filename) throws IOException { - BufferedWriter writer = null; - - try { - writer = new BufferedWriter(new FileWriter(filename)); - for (Row row: rows) { - List list = new ArrayList(row.cells.size()); - for (Cell cell: row.cells) { - list.add(cell.getText()); - } - writer.write(StringUtils.toCsv(list)); - writer.write("\n"); - } - } finally { - if (writer != null) { - writer.close(); - } - } - } - - /** - * Save contents to file in text format with lines. - * - * @param filename file to save to - * @throws IOException if a java.io operation throws - */ - public void saveToTextFilename(final String filename) throws IOException { - BufferedWriter writer = null; - - try { - writer = new BufferedWriter(new FileWriter(filename)); - - if ((topBorder == Border.SINGLE) && (leftBorder == Border.SINGLE)) { - // Emit top-left corner. - writer.write("\u250c"); - } - - if (topBorder == Border.SINGLE) { - int cellI = 0; - for (Cell cell: rows.get(0).cells) { - for (int i = 0; i < columns.get(cellI).width; i++) { - writer.write("\u2500"); - } - - if (columns.get(cellI).rightBorder == Border.SINGLE) { - if (cellI < columns.size() - 1) { - // Emit top tee. - writer.write("\u252c"); - } else { - // Emit top-right corner. - writer.write("\u2510"); - } - } - cellI++; - } - } - writer.write("\n"); - - int rowI = 0; - for (Row row: rows) { - - if (leftBorder == Border.SINGLE) { - // Emit left border. - writer.write("\u2502"); - } - - int cellI = 0; - for (Cell cell: row.cells) { - writer.write(String.format("%" + - columns.get(cellI).width + "s", cell.getText())); - - if (columns.get(cellI).rightBorder == Border.SINGLE) { - // Emit right border. - writer.write("\u2502"); - } - cellI++; - } - writer.write("\n"); - - if (row.bottomBorder == Border.NONE) { - // All done, move on to the next row. - continue; - } - - // Emit the bottom borders and intersections. - if ((leftBorder == Border.SINGLE) - && (row.bottomBorder != Border.NONE) - ) { - if (rowI < rows.size() - 1) { - if (row.bottomBorder == Border.SINGLE) { - // Emit left tee. - writer.write("\u251c"); - } else if (row.bottomBorder == Border.DOUBLE) { - // Emit left tee (double). - writer.write("\u255e"); - } else if (row.bottomBorder == Border.THICK) { - // Emit left tee (thick). - writer.write("\u251d"); - } - } - - if (rowI == rows.size() - 1) { - if (row.bottomBorder == Border.SINGLE) { - // Emit left bottom corner. - writer.write("\u2514"); - } else if (row.bottomBorder == Border.DOUBLE) { - // Emit left bottom corner (double). - writer.write("\u2558"); - } else if (row.bottomBorder == Border.THICK) { - // Emit left bottom corner (thick). - writer.write("\u2515"); - } - } - } - - cellI = 0; - for (Cell cell: row.cells) { - - for (int i = 0; i < columns.get(cellI).width; i++) { - if (row.bottomBorder == Border.SINGLE) { - writer.write("\u2500"); - } - if (row.bottomBorder == Border.DOUBLE) { - writer.write("\u2550"); - } - if (row.bottomBorder == Border.THICK) { - writer.write("\u2501"); - } - } - - if ((rowI < rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.SINGLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right tee. - writer.write("\u2524"); - } - if ((rowI < rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.DOUBLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right tee (double). - writer.write("\u2561"); - } - if ((rowI < rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.THICK) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right tee (thick). - writer.write("\u2525"); - } - if ((rowI == rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.SINGLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right bottom corner. - writer.write("\u2518"); - } - if ((rowI == rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.DOUBLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right bottom corner (double). - writer.write("\u255b"); - } - if ((rowI == rows.size() - 1) - && (cellI == columns.size() - 1) - && (row.bottomBorder == Border.THICK) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit right bottom corner (thick). - writer.write("\u2519"); - } - if ((rowI < rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.SINGLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit intersection. - writer.write("\u253c"); - } - if ((rowI < rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.DOUBLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit intersection (double). - writer.write("\u256a"); - } - if ((rowI < rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.THICK) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit intersection (thick). - writer.write("\u253f"); - } - if ((rowI == rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.SINGLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit bottom tee. - writer.write("\u2534"); - } - if ((rowI == rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.DOUBLE) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit bottom tee (double). - writer.write("\u2567"); - } - if ((rowI == rows.size() - 1) - && (cellI < columns.size() - 1) - && (row.bottomBorder == Border.THICK) - && (columns.get(cellI).rightBorder == Border.SINGLE) - ) { - // Emit bottom tee (thick). - writer.write("\u2537"); - } - - cellI++; - } - - writer.write("\n"); - rowI++; - } - } finally { - if (writer != null) { - writer.close(); - } - } - } - - /** - * Set the selected cell location. - * - * @param column the selected cell location column - * @param row the selected cell location row - */ - public void setSelectedCell(final int column, final int row) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - selectedColumn = column; - selectedRow = row; - alignGrid(); - } - - /** - * Get a particular cell. - * - * @param column the cell column - * @param row the cell row - * @return the cell - */ - public Cell getCell(final int column, final int row) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - return rows.get(row).get(column); - } - - /** - * Get the text of a particular cell. - * - * @param column the cell column - * @param row the cell row - * @return the text in the cell - */ - public String getCellText(final int column, final int row) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - return rows.get(row).get(column).getText(); - } - - /** - * Set the text of a particular cell. - * - * @param column the cell column - * @param row the cell row - * @param text the text to put into the cell - */ - public void setCellText(final int column, final int row, - final String text) { - - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - rows.get(row).get(column).setText(text); - } - - /** - * Set the action to perform when the user presses enter on a particular - * cell. - * - * @param column the cell column - * @param row the cell row - * @param action the action to perform when the user presses enter on the - * cell - */ - public void setCellEnterAction(final int column, final int row, - final TAction action) { - - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - rows.get(row).get(column).field.setEnterAction(action); - } - - /** - * Set the action to perform when the user updates a particular cell. - * - * @param column the cell column - * @param row the cell row - * @param action the action to perform when the user updates the cell - */ - public void setCellUpdateAction(final int column, final int row, - final TAction action) { - - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - rows.get(row).get(column).field.setUpdateAction(action); - } - - /** - * Get the width of a column. - * - * @param column the column number - * @return the width of the column - */ - public int getColumnWidth(final int column) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - return columns.get(column).width; - } - - /** - * Set the width of a column. - * - * @param column the column number - * @param width the new width of the column - */ - public void setColumnWidth(final int column, final int width) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - - if (width < 4) { - // Columns may not be smaller than 4 cells wide. - return; - } - - int delta = width - columns.get(column).width; - columns.get(column).width = width; - for (Cell cell: columns.get(column).cells) { - cell.setWidth(columns.get(column).width); - cell.field.setWidth(columns.get(column).width); - } - for (int i = column + 1; i < columns.size(); i++) { - columns.get(i).setX(columns.get(i).getX() + delta); - } - if (column == columns.size() - 1) { - bottomRightCorner(); - } else { - alignGrid(); - } - } - - /** - * Get the label of a column. - * - * @param column the column number - * @return the label of the column - */ - public String getColumnLabel(final int column) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - return columns.get(column).label; - } - - /** - * Set the label of a column. - * - * @param column the column number - * @param label the new label of the column - */ - public void setColumnLabel(final int column, final String label) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - columns.get(column).label = label; - } - - /** - * Get the label of a row. - * - * @param row the row number - * @return the label of the row - */ - public String getRowLabel(final int row) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - return rows.get(row).label; - } - - /** - * Set the label of a row. - * - * @param row the row number - * @param label the new label of the row - */ - public void setRowLabel(final int row, final String label) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - rows.get(row).label = label; - } - - /** - * Insert one row at a particular index. - * - * @param idx the row number - */ - private void insertRowAt(final int idx) { - Row newRow = new Row(idx); - for (int i = 0; i < columns.size(); i++) { - Cell cell = new Cell(this, columns.get(i).getX(), - rows.get(idx).getY(), COLUMN_DEFAULT_WIDTH, 1, i, idx); - newRow.add(cell); - columns.get(i).cells.add(idx, cell); - } - rows.add(idx, newRow); - - for (int x = 0; x < columns.size(); x++) { - for (int y = idx; y < rows.size(); y++) { - columns.get(x).get(y).row = y; - columns.get(x).get(y).column = x; - } - } - for (int i = idx + 1; i < rows.size(); i++) { - String oldRowLabel = Integer.toString(i - 1); - if (rows.get(i).label.equals(oldRowLabel)) { - rows.get(i).label = Integer.toString(i); - } - } - alignGrid(); - } - - /** - * Insert one row above a particular row. - * - * @param row the row number - */ - public void insertRowAbove(final int row) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - insertRowAt(row); - selectedRow++; - activate(columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Insert one row below a particular row. - * - * @param row the row number - */ - public void insertRowBelow(final int row) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - int idx = row + 1; - if (idx < rows.size()) { - insertRowAt(idx); - activate(columns.get(selectedColumn).get(selectedRow)); - return; - } - - // row is the last row, we need to perform an append. - Row newRow = new Row(idx); - for (int i = 0; i < columns.size(); i++) { - Cell cell = new Cell(this, columns.get(i).getX(), - rows.get(row).getY(), COLUMN_DEFAULT_WIDTH, 1, i, idx); - newRow.add(cell); - columns.get(i).cells.add(cell); - } - rows.add(newRow); - alignGrid(); - activate(columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Delete a particular row. - * - * @param row the row number - */ - public void deleteRow(final int row) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - if (rows.size() == 1) { - // Don't delete the last row. - return; - } - for (int i = 0; i < columns.size(); i++) { - Cell cell = columns.get(i).cells.remove(row); - getChildren().remove(cell); - } - rows.remove(row); - - for (int x = 0; x < columns.size(); x++) { - for (int y = row; y < rows.size(); y++) { - columns.get(x).get(y).row = y; - columns.get(x).get(y).column = x; - } - } - for (int i = row; i < rows.size(); i++) { - String oldRowLabel = Integer.toString(i + 1); - if (rows.get(i).label.equals(oldRowLabel)) { - rows.get(i).label = Integer.toString(i); - } - } - if (selectedRow == rows.size()) { - selectedRow--; - } - activate(columns.get(selectedColumn).get(selectedRow)); - bottomRightCorner(); - } - - /** - * Insert one column at a particular index. - * - * @param idx the column number - */ - private void insertColumnAt(final int idx) { - Column newColumn = new Column(idx); - for (int i = 0; i < rows.size(); i++) { - Cell cell = new Cell(this, columns.get(idx).getX(), - rows.get(i).getY(), COLUMN_DEFAULT_WIDTH, 1, idx, i); - newColumn.add(cell); - rows.get(i).cells.add(idx, cell); - } - columns.add(idx, newColumn); - - for (int x = idx; x < columns.size(); x++) { - for (int y = 0; y < rows.size(); y++) { - columns.get(x).get(y).row = y; - columns.get(x).get(y).column = x; - } - } - for (int i = idx + 1; i < columns.size(); i++) { - String oldColumnLabel = makeColumnLabel(i - 1); - if (columns.get(i).label.equals(oldColumnLabel)) { - columns.get(i).label = makeColumnLabel(i); - } - } - alignGrid(); - } - - /** - * Insert one column to the left of a particular column. - * - * @param column the column number - */ - public void insertColumnLeft(final int column) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - insertColumnAt(column); - selectedColumn++; - activate(columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Insert one column to the right of a particular column. - * - * @param column the column number - */ - public void insertColumnRight(final int column) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - int idx = column + 1; - if (idx < columns.size()) { - insertColumnAt(idx); - activate(columns.get(selectedColumn).get(selectedRow)); - return; - } - - // column is the last column, we need to perform an append. - Column newColumn = new Column(idx); - for (int i = 0; i < rows.size(); i++) { - Cell cell = new Cell(this, columns.get(column).getX(), - rows.get(i).getY(), COLUMN_DEFAULT_WIDTH, 1, idx, i); - newColumn.add(cell); - rows.get(i).cells.add(cell); - } - columns.add(newColumn); - alignGrid(); - activate(columns.get(selectedColumn).get(selectedRow)); - } - - /** - * Delete a particular column. - * - * @param column the column number - */ - public void deleteColumn(final int column) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if (columns.size() == 1) { - // Don't delete the last column. - return; - } - for (int i = 0; i < rows.size(); i++) { - Cell cell = rows.get(i).cells.remove(column); - getChildren().remove(cell); - } - columns.remove(column); - - for (int x = column; x < columns.size(); x++) { - for (int y = 0; y < rows.size(); y++) { - columns.get(x).get(y).row = y; - columns.get(x).get(y).column = x; - } - } - for (int i = column; i < columns.size(); i++) { - String oldColumnLabel = makeColumnLabel(i + 1); - if (columns.get(i).label.equals(oldColumnLabel)) { - columns.get(i).label = makeColumnLabel(i); - } - } - if (selectedColumn == columns.size()) { - selectedColumn--; - } - activate(columns.get(selectedColumn).get(selectedRow)); - bottomRightCorner(); - } - - /** - * Delete the selected cell, shifting cells over to the left. - */ - public void deleteCellShiftLeft() { - // All we do is copy the text from every cell in this row over. - for (int i = selectedColumn + 1; i < columns.size(); i++) { - setCellText(i - 1, selectedRow, getCellText(i, selectedRow)); - } - setCellText(columns.size() - 1, selectedRow, ""); - } - - /** - * Delete the selected cell, shifting cells from below up. - */ - public void deleteCellShiftUp() { - // All we do is copy the text from every cell in this column up. - for (int i = selectedRow + 1; i < rows.size(); i++) { - setCellText(selectedColumn, i - 1, getCellText(selectedColumn, i)); - } - setCellText(selectedColumn, rows.size() - 1, ""); - } - - /** - * Set a particular cell read-only (non-editable) or not. - * - * @param column the cell column - * @param row the cell row - * @param readOnly if true, the cell will be non-editable - */ - public void setCellReadOnly(final int column, final int row, - final boolean readOnly) { - - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - rows.get(row).get(column).setReadOnly(readOnly); - } - - /** - * Set an entire row of cells read-only (non-editable) or not. - * - * @param row the row number - * @param readOnly if true, the cells will be non-editable - */ - public void setRowReadOnly(final int row, final boolean readOnly) { - if ((row < 0) || (row > rows.size() - 1)) { - throw new IndexOutOfBoundsException("Row count is " + - rows.size() + ", requested index " + row); - } - for (Cell cell: rows.get(row).cells) { - cell.setReadOnly(readOnly); - } - } - - /** - * Set an entire column of cells read-only (non-editable) or not. - * - * @param column the column number - * @param readOnly if true, the cells will be non-editable - */ - public void setColumnReadOnly(final int column, final boolean readOnly) { - if ((column < 0) || (column > columns.size() - 1)) { - throw new IndexOutOfBoundsException("Column count is " + - columns.size() + ", requested index " + column); - } - for (Cell cell: columns.get(column).cells) { - cell.setReadOnly(readOnly); - } - } - - /** - * Set all borders across the entire table to Border.NONE. - */ - public void setBorderAllNone() { - topBorder = Border.NONE; - leftBorder = Border.NONE; - for (int i = 0; i < columns.size(); i++) { - columns.get(i).rightBorder = Border.NONE; - } - for (int i = 0; i < rows.size(); i++) { - rows.get(i).bottomBorder = Border.NONE; - rows.get(i).height = 1; - } - bottomRightCorner(); - } - - /** - * Set all borders across the entire table to Border.SINGLE. - */ - public void setBorderAllSingle() { - topBorder = Border.SINGLE; - leftBorder = Border.SINGLE; - for (int i = 0; i < columns.size(); i++) { - columns.get(i).rightBorder = Border.SINGLE; - } - for (int i = 0; i < rows.size(); i++) { - rows.get(i).bottomBorder = Border.SINGLE; - rows.get(i).height = 2; - } - alignGrid(); - } - - /** - * Set all borders around the selected cell to Border.NONE. - */ - public void setBorderCellNone() { - if (selectedRow == 0) { - topBorder = Border.NONE; - } - if (selectedColumn == 0) { - leftBorder = Border.NONE; - } - if (selectedColumn > 0) { - columns.get(selectedColumn - 1).rightBorder = Border.NONE; - } - columns.get(selectedColumn).rightBorder = Border.NONE; - if (selectedRow > 0) { - rows.get(selectedRow - 1).bottomBorder = Border.NONE; - rows.get(selectedRow - 1).height = 1; - } - rows.get(selectedRow).bottomBorder = Border.NONE; - rows.get(selectedRow).height = 1; - bottomRightCorner(); - } - - /** - * Set all borders around the selected cell to Border.SINGLE. - */ - public void setBorderCellSingle() { - if (selectedRow == 0) { - topBorder = Border.SINGLE; - } - if (selectedColumn == 0) { - leftBorder = Border.SINGLE; - } - if (selectedColumn > 0) { - columns.get(selectedColumn - 1).rightBorder = Border.SINGLE; - } - columns.get(selectedColumn).rightBorder = Border.SINGLE; - if (selectedRow > 0) { - rows.get(selectedRow - 1).bottomBorder = Border.SINGLE; - rows.get(selectedRow - 1).height = 2; - } - rows.get(selectedRow).bottomBorder = Border.SINGLE; - rows.get(selectedRow).height = 2; - alignGrid(); - } - - /** - * Set the column border to the right of the selected cell to - * Border.SINGLE. - */ - public void setBorderColumnRightSingle() { - columns.get(selectedColumn).rightBorder = Border.SINGLE; - alignGrid(); - } - - /** - * Set the column border to the right of the selected cell to - * Border.SINGLE. - */ - public void setBorderColumnLeftSingle() { - if (selectedColumn == 0) { - leftBorder = Border.SINGLE; - } else { - columns.get(selectedColumn - 1).rightBorder = Border.SINGLE; - } - alignGrid(); - } - - /** - * Set the row border above the selected cell to Border.SINGLE. - */ - public void setBorderRowAboveSingle() { - if (selectedRow == 0) { - topBorder = Border.SINGLE; - } else { - rows.get(selectedRow - 1).bottomBorder = Border.SINGLE; - rows.get(selectedRow - 1).height = 2; - } - alignGrid(); - } - - /** - * Set the row border below the selected cell to Border.SINGLE. - */ - public void setBorderRowBelowSingle() { - rows.get(selectedRow).bottomBorder = Border.SINGLE; - rows.get(selectedRow).height = 2; - alignGrid(); - } - - /** - * Set the row border below the selected cell to Border.DOUBLE. - */ - public void setBorderRowBelowDouble() { - rows.get(selectedRow).bottomBorder = Border.DOUBLE; - rows.get(selectedRow).height = 2; - alignGrid(); - } - - /** - * Set the row border below the selected cell to Border.THICK. - */ - public void setBorderRowBelowThick() { - rows.get(selectedRow).bottomBorder = Border.THICK; - rows.get(selectedRow).height = 2; - alignGrid(); - } - -}