2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.io
.IOException
;
32 import java
.util
.ArrayList
;
33 import java
.util
.List
;
35 import jexer
.bits
.CellAttributes
;
36 import jexer
.event
.TKeypressEvent
;
37 import jexer
.event
.TMouseEvent
;
38 import jexer
.event
.TResizeEvent
;
39 import static jexer
.TKeypress
.*;
42 * TTableWidget is used to display and edit regular two-dimensional tables of
45 * This class was inspired by a TTable implementation originally developed by
46 * David "Niki" ROULET [niki@nikiroo.be], made available under MIT at
47 * https://github.com/nikiroo/jexer/tree/ttable_pull.
49 public class TTableWidget
extends TWidget
{
51 // ------------------------------------------------------------------------
52 // Constants --------------------------------------------------------------
53 // ------------------------------------------------------------------------
56 * Available borders for cells.
65 * Single bar: \u2502 (vertical) and \u2500 (horizontal).
70 * Double bar: \u2551 (vertical) and \u2550 (horizontal).
75 * Thick bar: \u2503 (vertical heavy) and \u2501 (horizontal heavy).
81 * If true, put a grid of numbers in the cells.
83 private static final boolean DEBUG
= false;
88 private static final int ROW_LABEL_WIDTH
= 8;
91 * Column label height.
93 private static final int COLUMN_LABEL_HEIGHT
= 1;
96 * Column default width.
98 private static final int COLUMN_DEFAULT_WIDTH
= 8;
103 private static final int EXTRA_ROWS
= (DEBUG ?
10 : 0);
106 * Extra columns to add.
108 private static final int EXTRA_COLUMNS
= (DEBUG ?
10 * (8 + 1) : 0);
110 // ------------------------------------------------------------------------
111 // Variables --------------------------------------------------------------
112 // ------------------------------------------------------------------------
115 * The underlying data, organized as columns.
117 private ArrayList
<Column
> columns
= new ArrayList
<Column
>();
120 * The underlying data, organized as rows.
122 private ArrayList
<Row
> rows
= new ArrayList
<Row
>();
125 * The row in model corresponding to the top-left visible cell.
130 * The column in model corresponding to the top-left visible cell.
132 private int left
= 0;
135 * The row in model corresponding to the currently selected cell.
137 private int selectedRow
= 0;
140 * The column in model corresponding to the currently selected cell.
142 private int selectedColumn
= 0;
145 * If true, highlight the entire row of the currently-selected cell.
147 private boolean highlightRow
= false;
150 * If true, highlight the entire column of the currently-selected cell.
152 private boolean highlightColumn
= false;
155 * If true, show the row labels as the first column.
157 private boolean showRowLabels
= true;
160 * If true, show the column labels as the first row.
162 private boolean showColumnLabels
= true;
165 * The top border for the first row.
167 private Border topBorder
= Border
.NONE
;
170 * The left border for the first column.
172 private Border leftBorder
= Border
.NONE
;
175 * Column represents a column of cells.
177 public class Column
{
180 * X position of this column.
187 private int width
= COLUMN_DEFAULT_WIDTH
;
190 * The cells of this column.
192 private ArrayList
<Cell
> cells
= new ArrayList
<Cell
>();
197 private String label
= "";
200 * The right border for this column.
202 private Border rightBorder
= Border
.NONE
;
205 * Constructor sets label to lettered column.
207 * @param col column number to use for this column. Column 0 will be
208 * "A", column 1 will be "B", column 26 will be "AA", and so on.
211 label
= makeColumnLabel(col
);
215 * Add an entry to this column.
217 * @param cell the cell to add
219 public void add(final Cell cell
) {
224 * Get an entry from this column.
226 * @param row the entry index to get
227 * @return the cell at row
229 public Cell
get(final int row
) {
230 return cells
.get(row
);
234 * Get the X position of the cells in this column.
236 * @return the position
243 * Set the X position of the cells in this column.
245 * @param x the position
247 public void setX(final int x
) {
248 for (Cell cell
: cells
) {
257 * Row represents a row of cells.
262 * Y position of this row.
269 private int height
= 1;
272 * The cells of this row.
274 private ArrayList
<Cell
> cells
= new ArrayList
<Cell
>();
279 private String label
= "";
282 * The bottom border for this row.
284 private Border bottomBorder
= Border
.NONE
;
287 * Constructor sets label to numbered row.
289 * @param row row number to use for this row
292 label
= Integer
.toString(row
);
296 * Add an entry to this column.
298 * @param cell the cell to add
300 public void add(final Cell cell
) {
305 * Get an entry from this row.
307 * @param column the entry index to get
308 * @return the cell at column
310 public Cell
get(final int column
) {
311 return cells
.get(column
);
314 * Get the Y position of the cells in this column.
316 * @return the position
323 * Set the Y position of the cells in this column.
325 * @param y the position
327 public void setY(final int y
) {
328 for (Cell cell
: cells
) {
337 * Cell represents an editable cell in the table. Normally, navigation
338 * to a cell only highlights it; pressing Enter or F2 will switch to
341 public class Cell
extends TWidget
{
343 // --------------------------------------------------------------------
344 // Variables ----------------------------------------------------------
345 // --------------------------------------------------------------------
348 * The field containing the cell's data.
350 private TField field
;
353 * The column of this cell.
358 * The row of this cell.
363 * If true, the cell is being edited.
365 private boolean isEditing
= false;
368 * If true, the cell is read-only (non-editable).
370 private boolean readOnly
= false;
373 * Text of field before editing.
375 private String fieldText
;
377 // --------------------------------------------------------------------
378 // Constructors -------------------------------------------------------
379 // --------------------------------------------------------------------
382 * Public constructor.
384 * @param parent parent widget
385 * @param x column relative to parent
386 * @param y row relative to parent
387 * @param width width of widget
388 * @param height height of widget
389 * @param column column index of this cell
390 * @param row row index of this cell
392 public Cell(final TTableWidget parent
, final int x
, final int y
,
393 final int width
, final int height
, final int column
,
396 super(parent
, x
, y
, width
, height
);
397 this.column
= column
;
400 field
= addField(0, 0, width
, false);
401 field
.setEnabled(false);
402 field
.setBackgroundChar(' ');
405 // --------------------------------------------------------------------
406 // Event handlers -----------------------------------------------------
407 // --------------------------------------------------------------------
410 * Handle mouse double-click events.
412 * @param mouse mouse double-click event
415 public void onMouseDoubleClick(final TMouseEvent mouse
) {
416 // Use TWidget's code to pass the event to the children.
417 super.onMouseDown(mouse
);
419 // Double-click means to start editing.
420 fieldText
= field
.getText();
422 field
.setEnabled(true);
426 // Let the table know that I was activated.
427 ((TTableWidget
) getParent()).selectedRow
= row
;
428 ((TTableWidget
) getParent()).selectedColumn
= column
;
429 ((TTableWidget
) getParent()).alignGrid();
434 * Handle mouse press events.
436 * @param mouse mouse button press event
439 public void onMouseDown(final TMouseEvent mouse
) {
440 // Use TWidget's code to pass the event to the children.
441 super.onMouseDown(mouse
);
444 // Let the table know that I was activated.
445 ((TTableWidget
) getParent()).selectedRow
= row
;
446 ((TTableWidget
) getParent()).selectedColumn
= column
;
447 ((TTableWidget
) getParent()).alignGrid();
452 * Handle mouse release events.
454 * @param mouse mouse button release event
457 public void onMouseUp(final TMouseEvent mouse
) {
458 // Use TWidget's code to pass the event to the children.
459 super.onMouseDown(mouse
);
462 // Let the table know that I was activated.
463 ((TTableWidget
) getParent()).selectedRow
= row
;
464 ((TTableWidget
) getParent()).selectedColumn
= column
;
465 ((TTableWidget
) getParent()).alignGrid();
472 * @param keypress keystroke event
475 public void onKeypress(final TKeypressEvent keypress
) {
476 // System.err.println("Cell onKeypress: " + keypress);
479 // Read only: do nothing.
484 if (keypress
.equals(kbEsc
)) {
485 // ESC cancels the edit.
489 if (keypress
.equals(kbEnter
)) {
490 // Enter ends editing.
492 // Pass down to field first so that it can execute
493 // enterAction if specified.
494 super.onKeypress(keypress
);
496 fieldText
= field
.getText();
498 field
.setEnabled(false);
501 // Pass down to field.
502 super.onKeypress(keypress
);
505 if (keypress
.equals(kbEnter
) || keypress
.equals(kbF2
)) {
506 // Enter or F2 starts editing.
507 fieldText
= field
.getText();
509 field
.setEnabled(true);
515 // --------------------------------------------------------------------
516 // TWidget ------------------------------------------------------------
517 // --------------------------------------------------------------------
524 TTableWidget table
= (TTableWidget
) getParent();
526 if (isAbsoluteActive()) {
528 field
.setActiveColorKey("tfield.active");
529 field
.setInactiveColorKey("tfield.inactive");
531 field
.setActiveColorKey("ttable.selected");
532 field
.setInactiveColorKey("ttable.selected");
534 } else if (((table
.selectedColumn
== column
)
535 && ((table
.selectedRow
== row
)
536 || (table
.highlightColumn
== true)))
537 || ((table
.selectedRow
== row
)
538 && ((table
.selectedColumn
== column
)
539 || (table
.highlightRow
== true)))
541 field
.setActiveColorKey("ttable.active");
542 field
.setInactiveColorKey("ttable.active");
544 field
.setActiveColorKey("ttable.active");
545 field
.setInactiveColorKey("ttable.inactive");
548 assert (isVisible() == true);
553 // --------------------------------------------------------------------
554 // TTable.Cell --------------------------------------------------------
555 // --------------------------------------------------------------------
562 public final String
getText() {
563 return field
.getText();
569 * @param text the new field text
571 public void setText(final String text
) {
576 * Cancel any pending edit.
578 public void cancelEdit() {
579 // Cancel any pending edit.
580 if (fieldText
!= null) {
581 field
.setText(fieldText
);
584 field
.setEnabled(false);
588 * Set an entire column of cells read-only (non-editable) or not.
590 * @param readOnly if true, the cells will be non-editable
592 public void setReadOnly(final boolean readOnly
) {
594 this.readOnly
= readOnly
;
599 // ------------------------------------------------------------------------
600 // Constructors -----------------------------------------------------------
601 // ------------------------------------------------------------------------
604 * Public constructor.
606 * @param parent parent widget
607 * @param x column relative to parent
608 * @param y row relative to parent
609 * @param width width of widget
610 * @param height height of widget
612 public TTableWidget(final TWidget parent
, final int x
, final int y
,
613 final int width
, final int height
) {
615 super(parent
, x
, y
, width
, height
);
617 // Initialize the starting row and column.
618 rows
.add(new Row(0));
619 columns
.add(new Column(0));
621 // Place a grid of cells that fit in this space.
623 for (int i
= 0; i
< height
+ EXTRA_ROWS
; i
+= rows
.get(0).height
) {
625 for (int j
= 0; j
< width
+ EXTRA_COLUMNS
;
626 j
+= columns
.get(0).width
) {
628 Cell cell
= new Cell(this, 0, 0, columns
.get(0).width
,
629 rows
.get(0).height
, column
, row
);
632 // For debugging: set a grid of cell index labels.
633 cell
.setText("" + row
+ " " + column
);
635 rows
.get(row
).add(cell
);
636 columns
.get(column
).add(cell
);
638 (j
+ columns
.get(0).width
< width
+ EXTRA_COLUMNS
)
640 columns
.add(new Column(column
+ 1));
644 if (i
+ rows
.get(0).height
< height
+ EXTRA_ROWS
) {
645 rows
.add(new Row(row
+ 1));
649 for (int i
= 0; i
< rows
.size(); i
++) {
650 rows
.get(i
).setY(i
+ (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0));
652 for (int j
= 0; j
< columns
.size(); j
++) {
653 columns
.get(j
).setX((j
* COLUMN_DEFAULT_WIDTH
) +
654 (showRowLabels ? ROW_LABEL_WIDTH
: 0));
656 activate(columns
.get(selectedColumn
).get(selectedRow
));
661 // ------------------------------------------------------------------------
662 // Event handlers ---------------------------------------------------------
663 // ------------------------------------------------------------------------
666 * Handle mouse press events.
668 * @param mouse mouse button press event
671 public void onMouseDown(final TMouseEvent mouse
) {
672 if (mouse
.isMouseWheelUp() || mouse
.isMouseWheelDown()) {
673 // Treat wheel up/down as 3 up/down
674 TKeypressEvent keyEvent
;
675 if (mouse
.isMouseWheelUp()) {
676 keyEvent
= new TKeypressEvent(kbUp
);
678 keyEvent
= new TKeypressEvent(kbDown
);
680 for (int i
= 0; i
< 3; i
++) {
681 onKeypress(keyEvent
);
686 // Use TWidget's code to pass the event to the children.
687 super.onMouseDown(mouse
);
693 * @param keypress keystroke event
696 public void onKeypress(final TKeypressEvent keypress
) {
697 if (keypress
.equals(kbTab
)
698 || keypress
.equals(kbShiftTab
)
700 // Squash tab and back-tab. They don't make sense in the TTable
705 // If editing, pass to that cell and do nothing else.
706 if (getSelectedCell().isEditing
) {
707 super.onKeypress(keypress
);
711 if (keypress
.equals(kbLeft
)) {
713 if (selectedColumn
> 0) {
716 activate(columns
.get(selectedColumn
).get(selectedRow
));
717 } else if (keypress
.equals(kbRight
)) {
719 if (selectedColumn
< columns
.size() - 1) {
722 activate(columns
.get(selectedColumn
).get(selectedRow
));
723 } else if (keypress
.equals(kbUp
)) {
725 if (selectedRow
> 0) {
728 activate(columns
.get(selectedColumn
).get(selectedRow
));
729 } else if (keypress
.equals(kbDown
)) {
731 if (selectedRow
< rows
.size() - 1) {
734 activate(columns
.get(selectedColumn
).get(selectedRow
));
735 } else if (keypress
.equals(kbHome
)) {
736 // Home - leftmost column
738 activate(columns
.get(selectedColumn
).get(selectedRow
));
739 } else if (keypress
.equals(kbEnd
)) {
740 // End - rightmost column
741 selectedColumn
= columns
.size() - 1;
742 activate(columns
.get(selectedColumn
).get(selectedRow
));
743 } else if (keypress
.equals(kbPgUp
)) {
744 // PgUp - Treat like multiple up
745 for (int i
= 0; i
< getHeight() - 2; i
++) {
746 if (selectedRow
> 0) {
750 activate(columns
.get(selectedColumn
).get(selectedRow
));
751 } else if (keypress
.equals(kbPgDn
)) {
752 // PgDn - Treat like multiple up
753 for (int i
= 0; i
< getHeight() - 2; i
++) {
754 if (selectedRow
< rows
.size() - 1) {
758 activate(columns
.get(selectedColumn
).get(selectedRow
));
759 } else if (keypress
.equals(kbCtrlHome
)) {
760 // Ctrl-Home - go to top-left
763 activate(columns
.get(selectedColumn
).get(selectedRow
));
764 activate(columns
.get(selectedColumn
).get(selectedRow
));
765 } else if (keypress
.equals(kbCtrlEnd
)) {
766 // Ctrl-End - go to bottom-right
767 selectedRow
= rows
.size() - 1;
768 selectedColumn
= columns
.size() - 1;
769 activate(columns
.get(selectedColumn
).get(selectedRow
));
770 activate(columns
.get(selectedColumn
).get(selectedRow
));
773 super.onKeypress(keypress
);
776 // We may have scrolled off screen. Reset positions as needed to
777 // make the newly selected cell visible.
782 * Handle widget resize events.
784 * @param event resize event
787 public void onResize(final TResizeEvent event
) {
788 super.onResize(event
);
793 // ------------------------------------------------------------------------
794 // TWidget ----------------------------------------------------------------
795 // ------------------------------------------------------------------------
798 * Draw the table row/column labels, and borders.
802 CellAttributes labelColor
= getTheme().getColor("ttable.label");
803 CellAttributes labelColorSelected
= getTheme().getColor("ttable.label.selected");
804 CellAttributes borderColor
= getTheme().getColor("ttable.border");
807 if (showColumnLabels
== true) {
808 for (int i
= left
; i
< columns
.size(); i
++) {
809 if (columns
.get(i
).get(top
).isVisible() == false) {
812 putStringXY(columns
.get(i
).get(top
).getX(), 0,
813 String
.format(" %-" +
814 (columns
.get(i
).width
- 2)
815 + "s ", columns
.get(i
).label
),
816 (i
== selectedColumn ? labelColorSelected
: labelColor
));
821 if (showRowLabels
== true) {
822 for (int i
= top
; i
< rows
.size(); i
++) {
823 if (rows
.get(i
).get(left
).isVisible() == false) {
826 putStringXY(0, rows
.get(i
).get(left
).getY(),
827 String
.format(" %-6s ", rows
.get(i
).label
),
828 (i
== selectedRow ? labelColorSelected
: labelColor
));
832 // Draw vertical borders.
833 if (leftBorder
== Border
.SINGLE
) {
834 vLineXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
835 (topBorder
== Border
.NONE ?
0 : 1) +
836 (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0),
837 getHeight(), '\u2502', borderColor
);
839 for (int i
= left
; i
< columns
.size(); i
++) {
840 if (columns
.get(i
).get(top
).isVisible() == false) {
843 if (columns
.get(i
).rightBorder
== Border
.SINGLE
) {
844 vLineXY(columns
.get(i
).getX() + columns
.get(i
).width
,
845 (topBorder
== Border
.NONE ?
0 : 1) +
846 (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0),
847 getHeight(), '\u2502', borderColor
);
851 // Draw horizontal borders.
852 if (topBorder
== Border
.SINGLE
) {
853 hLineXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
854 (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0),
855 getWidth(), '\u2500', borderColor
);
857 for (int i
= top
; i
< rows
.size(); i
++) {
858 if (rows
.get(i
).get(left
).isVisible() == false) {
861 if (rows
.get(i
).bottomBorder
== Border
.SINGLE
) {
862 hLineXY((leftBorder
== Border
.NONE ?
0 : 1) +
863 (showRowLabels ? ROW_LABEL_WIDTH
: 0),
864 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
865 getWidth(), '\u2500', borderColor
);
866 } else if (rows
.get(i
).bottomBorder
== Border
.DOUBLE
) {
867 hLineXY((leftBorder
== Border
.NONE ?
0 : 1) +
868 (showRowLabels ? ROW_LABEL_WIDTH
: 0),
869 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
870 getWidth(), '\u2550', borderColor
);
871 } else if (rows
.get(i
).bottomBorder
== Border
.THICK
) {
872 hLineXY((leftBorder
== Border
.NONE ?
0 : 1) +
873 (showRowLabels ? ROW_LABEL_WIDTH
: 0),
874 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
875 getWidth(), '\u2501', borderColor
);
878 // Top-left corner if needed
879 if ((topBorder
== Border
.SINGLE
) && (leftBorder
== Border
.SINGLE
)) {
880 putCharXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
881 (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0),
882 '\u250c', borderColor
);
885 // Now draw the correct corners
886 for (int i
= top
; i
< rows
.size(); i
++) {
887 if (rows
.get(i
).get(left
).isVisible() == false) {
890 for (int j
= left
; j
< columns
.size(); j
++) {
891 if (columns
.get(j
).get(i
).isVisible() == false) {
894 if ((i
== top
) && (topBorder
== Border
.SINGLE
)
895 && (columns
.get(j
).rightBorder
== Border
.SINGLE
)
898 putCharXY(columns
.get(j
).getX() + columns
.get(j
).width
,
899 (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0),
900 '\u252c', borderColor
);
902 if ((j
== left
) && (leftBorder
== Border
.SINGLE
)
903 && (rows
.get(i
).bottomBorder
== Border
.SINGLE
)
906 putCharXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
907 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
908 '\u251c', borderColor
);
910 if ((columns
.get(j
).rightBorder
== Border
.SINGLE
)
911 && (rows
.get(i
).bottomBorder
== Border
.SINGLE
)
913 // Intersection of single bars
914 putCharXY(columns
.get(j
).getX() + columns
.get(j
).width
,
915 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
916 '\u253c', borderColor
);
918 if ((j
== left
) && (leftBorder
== Border
.SINGLE
)
919 && (rows
.get(i
).bottomBorder
== Border
.DOUBLE
)
921 // Left tee: single bar vertical, double bar horizontal
922 putCharXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
923 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
924 '\u255e', borderColor
);
926 if ((j
== left
) && (leftBorder
== Border
.SINGLE
)
927 && (rows
.get(i
).bottomBorder
== Border
.THICK
)
929 // Left tee: single bar vertical, thick bar horizontal
930 putCharXY((showRowLabels ? ROW_LABEL_WIDTH
: 0),
931 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
932 '\u251d', borderColor
);
934 if ((columns
.get(j
).rightBorder
== Border
.SINGLE
)
935 && (rows
.get(i
).bottomBorder
== Border
.DOUBLE
)
937 // Intersection: single bar vertical, double bar
939 putCharXY(columns
.get(j
).getX() + columns
.get(j
).width
,
940 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
941 '\u256a', borderColor
);
943 if ((columns
.get(j
).rightBorder
== Border
.SINGLE
)
944 && (rows
.get(i
).bottomBorder
== Border
.THICK
)
946 // Intersection: single bar vertical, thick bar
948 putCharXY(columns
.get(j
).getX() + columns
.get(j
).width
,
949 rows
.get(i
).getY() + rows
.get(i
).height
- 1,
950 '\u253f', borderColor
);
955 // Now draw the window borders.
959 // ------------------------------------------------------------------------
960 // TTable -----------------------------------------------------------------
961 // ------------------------------------------------------------------------
964 * Generate the default letter name for a column number.
966 * @param col column number to use for this column. Column 0 will be
967 * "A", column 1 will be "B", column 26 will be "AA", and so on.
969 private String
makeColumnLabel(int col
) {
970 StringBuilder sb
= new StringBuilder();
972 sb
.append((char) ('A' + (col
% 26)));
978 return sb
.reverse().toString();
982 * Get the currently-selected cell.
984 * @return the selected cell
986 public Cell
getSelectedCell() {
987 assert (rows
.get(selectedRow
) != null);
988 assert (rows
.get(selectedRow
).get(selectedColumn
) != null);
989 assert (columns
.get(selectedColumn
) != null);
990 assert (columns
.get(selectedColumn
).get(selectedRow
) != null);
991 assert (rows
.get(selectedRow
).get(selectedColumn
) ==
992 columns
.get(selectedColumn
).get(selectedRow
));
994 return (columns
.get(selectedColumn
).get(selectedRow
));
998 * Get the currently-selected column.
1000 * @return the selected column
1002 public Column
getSelectedColumn() {
1003 assert (selectedColumn
>= 0);
1004 assert (columns
.size() > selectedColumn
);
1005 assert (columns
.get(selectedColumn
) != null);
1006 return columns
.get(selectedColumn
);
1010 * Get the currently-selected row.
1012 * @return the selected row
1014 public Row
getSelectedRow() {
1015 assert (selectedRow
>= 0);
1016 assert (rows
.size() > selectedRow
);
1017 assert (rows
.get(selectedRow
) != null);
1018 return rows
.get(selectedRow
);
1022 * Get the currently-selected column number. 0 is the left-most column.
1024 * @return the selected column number
1026 public int getSelectedColumnNumber() {
1027 return selectedColumn
;
1031 * Set the currently-selected column number. 0 is the left-most column.
1033 * @param column the column number to select
1035 public void setSelectedColumnNumber(final int column
) {
1036 if ((column
< 0) || (column
> columns
.size() - 1)) {
1037 throw new IndexOutOfBoundsException("Column count is " +
1038 columns
.size() + ", requested index " + column
);
1040 selectedColumn
= column
;
1041 activate(columns
.get(selectedColumn
).get(selectedRow
));
1046 * Get the currently-selected row number. 0 is the top-most row.
1048 * @return the selected row number
1050 public int getSelectedRowNumber() {
1055 * Set the currently-selected row number. 0 is the left-most column.
1057 * @param row the row number to select
1059 public void setSelectedRowNumber(final int row
) {
1060 if ((row
< 0) || (row
> rows
.size() - 1)) {
1061 throw new IndexOutOfBoundsException("Row count is " +
1062 rows
.size() + ", requested index " + row
);
1065 activate(columns
.get(selectedColumn
).get(selectedRow
));
1070 * Get the highlight row flag.
1072 * @return true if the selected row is highlighted
1074 public boolean getHighlightRow() {
1075 return highlightRow
;
1079 * Set the highlight row flag.
1081 * @param highlightRow if true, the selected row will be highlighted
1083 public void setHighlightRow(final boolean highlightRow
) {
1084 this.highlightRow
= highlightRow
;
1088 * Get the highlight column flag.
1090 * @return true if the selected column is highlighted
1092 public boolean getHighlightColumn() {
1093 return highlightColumn
;
1097 * Set the highlight column flag.
1099 * @param highlightColumn if true, the selected column will be highlighted
1101 public void setHighlightColumn(final boolean highlightColumn
) {
1102 this.highlightColumn
= highlightColumn
;
1106 * Get the show row labels flag.
1108 * @return true if row labels are shown
1110 public boolean getShowRowLabels() {
1111 return showRowLabels
;
1115 * Set the show row labels flag.
1117 * @param showRowLabels if true, the row labels will be shown
1119 public void setShowRowLabels(final boolean showRowLabels
) {
1120 this.showRowLabels
= showRowLabels
;
1124 * Get the show column labels flag.
1126 * @return true if column labels are shown
1128 public boolean getShowColumnLabels() {
1129 return showColumnLabels
;
1133 * Set the show column labels flag.
1135 * @param showColumnLabels if true, the column labels will be shown
1137 public void setShowColumnLabels(final boolean showColumnLabels
) {
1138 this.showColumnLabels
= showColumnLabels
;
1142 * Get the number of columns.
1144 * @return the number of columns
1146 public int getColumnCount() {
1147 return columns
.size();
1151 * Get the number of rows.
1153 * @return the number of rows
1155 public int getRowCount() {
1161 * Push top and left to the bottom-most right corner of the available
1164 private void bottomRightCorner() {
1165 int viewColumns
= getWidth();
1166 if (showRowLabels
== true) {
1167 viewColumns
-= ROW_LABEL_WIDTH
;
1170 // Set left and top such that the table stays on screen if possible.
1171 top
= rows
.size() - getHeight();
1172 left
= columns
.size() - (getWidth() / (viewColumns
/ (COLUMN_DEFAULT_WIDTH
+ 1)));
1173 // Now ensure the selection is visible.
1178 * Align the grid so that the selected cell is fully visible.
1180 private void alignGrid() {
1181 int viewColumns
= getWidth();
1182 if (showRowLabels
== true) {
1183 viewColumns
-= ROW_LABEL_WIDTH
;
1185 if (leftBorder
!= Border
.NONE
) {
1188 int viewRows
= getHeight();
1189 if (showColumnLabels
== true) {
1190 viewRows
-= COLUMN_LABEL_HEIGHT
;
1192 if (topBorder
!= Border
.NONE
) {
1196 // If we pushed left or right, adjust the box to include the new
1198 if (selectedColumn
< left
) {
1199 left
= selectedColumn
- 1;
1204 if (selectedRow
< top
) {
1205 top
= selectedRow
- 1;
1212 * viewColumns and viewRows now contain the available columns and
1213 * rows available to view the selected cell. We adjust left and top
1214 * to ensure the selected cell is within view, and then make all
1215 * cells outside the box between (left, top) and (right, bottom)
1218 * We need to calculate right and bottom now.
1222 boolean done
= false;
1224 int rightCellX
= (showRowLabels ? ROW_LABEL_WIDTH
: 0);
1225 if (leftBorder
!= Border
.NONE
) {
1228 int maxCellX
= rightCellX
+ viewColumns
;
1230 boolean selectedIsVisible
= false;
1232 for (int x
= left
; x
< columns
.size(); x
++) {
1233 if (x
== selectedColumn
) {
1234 selectedX
= rightCellX
;
1235 if (selectedX
+ columns
.get(x
).width
+ 1 <= maxCellX
) {
1236 selectedIsVisible
= true;
1239 rightCellX
+= columns
.get(x
).width
+ 1;
1240 if (rightCellX
>= maxCellX
) {
1245 if (right
< selectedColumn
) {
1246 // selectedColumn is outside the view range. Push left over,
1247 // and calculate again.
1249 } else if (left
== selectedColumn
) {
1250 // selectedColumn doesn't fit inside the view range, but we
1251 // can't go over any further either. Bail out.
1253 } else if (selectedIsVisible
== false) {
1254 // selectedColumn doesn't fit inside the view range, continue
1258 // selectedColumn is fully visible, all done.
1259 assert (selectedIsVisible
== true);
1265 // We have the left/right range correct, set cell visibility and
1266 // column X positions.
1267 int leftCellX
= showRowLabels ? ROW_LABEL_WIDTH
: 0;
1268 if (leftBorder
!= Border
.NONE
) {
1271 for (int x
= 0; x
< columns
.size(); x
++) {
1272 if ((x
< left
) || (x
> right
)) {
1273 for (int i
= 0; i
< rows
.size(); i
++) {
1274 columns
.get(x
).get(i
).setVisible(false);
1275 columns
.get(x
).setX(getWidth() + 1);
1279 for (int i
= 0; i
< rows
.size(); i
++) {
1280 columns
.get(x
).get(i
).setVisible(true);
1282 columns
.get(x
).setX(leftCellX
);
1283 leftCellX
+= columns
.get(x
).width
+ 1;
1290 int bottomCellY
= (showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0);
1291 if (topBorder
!= Border
.NONE
) {
1294 int maxCellY
= bottomCellY
+ viewRows
;
1296 for (int y
= top
; y
< rows
.size(); y
++) {
1297 bottomCellY
+= rows
.get(y
).height
;
1298 if (bottomCellY
>= maxCellY
) {
1303 if (bottom
< selectedRow
) {
1304 // selectedRow is outside the view range. Push top down, and
1308 // selectedRow is inside the view range, done.
1313 // We have the top/bottom range correct, set cell visibility and
1315 int topCellY
= showColumnLabels ? COLUMN_LABEL_HEIGHT
: 0;
1316 if (topBorder
!= Border
.NONE
) {
1319 for (int y
= 0; y
< rows
.size(); y
++) {
1320 if ((y
< top
) || (y
> bottom
)) {
1321 for (int i
= 0; i
< columns
.size(); i
++) {
1322 rows
.get(y
).get(i
).setVisible(false);
1324 rows
.get(y
).setY(getHeight() + 1);
1327 for (int i
= 0; i
< columns
.size(); i
++) {
1328 rows
.get(y
).get(i
).setVisible(true);
1330 rows
.get(y
).setY(topCellY
);
1331 topCellY
+= rows
.get(y
).height
;
1334 // Last thing: cancel any edits that are not the selected cell.
1335 for (int y
= 0; y
< rows
.size(); y
++) {
1336 for (int x
= 0; x
< columns
.size(); x
++) {
1337 if ((x
== selectedColumn
) && (y
== selectedRow
)) {
1340 rows
.get(y
).get(x
).cancelEdit();
1346 * Save contents to file in CSV format.
1348 * @param filename file to save to
1349 * @throws IOException if a java.io operation throws
1351 public void saveToCsvFilename(final String filename
) throws IOException
{
1356 * Save contents to file in text format with lines.
1358 * @param filename file to save to
1359 * @throws IOException if a java.io operation throws
1361 public void saveToTextFilename(final String filename
) throws IOException
{
1366 * Set the selected cell location.
1368 * @param column the selected cell location column
1369 * @param row the selected cell location row
1371 public void setSelectedCell(final int column
, final int row
) {
1372 if ((column
< 0) || (column
> columns
.size() - 1)) {
1373 throw new IndexOutOfBoundsException("Column count is " +
1374 columns
.size() + ", requested index " + column
);
1376 if ((row
< 0) || (row
> rows
.size() - 1)) {
1377 throw new IndexOutOfBoundsException("Row count is " +
1378 rows
.size() + ", requested index " + row
);
1380 selectedColumn
= column
;
1386 * Get a particular cell.
1388 * @param column the cell column
1389 * @param row the cell row
1392 public Cell
getCell(final int column
, final int row
) {
1393 if ((column
< 0) || (column
> columns
.size() - 1)) {
1394 throw new IndexOutOfBoundsException("Column count is " +
1395 columns
.size() + ", requested index " + column
);
1397 if ((row
< 0) || (row
> rows
.size() - 1)) {
1398 throw new IndexOutOfBoundsException("Row count is " +
1399 rows
.size() + ", requested index " + row
);
1401 return rows
.get(row
).get(column
);
1405 * Get the text of a particular cell.
1407 * @param column the cell column
1408 * @param row the cell row
1409 * @return the text in the cell
1411 public String
getCellText(final int column
, final int row
) {
1412 if ((column
< 0) || (column
> columns
.size() - 1)) {
1413 throw new IndexOutOfBoundsException("Column count is " +
1414 columns
.size() + ", requested index " + column
);
1416 if ((row
< 0) || (row
> rows
.size() - 1)) {
1417 throw new IndexOutOfBoundsException("Row count is " +
1418 rows
.size() + ", requested index " + row
);
1420 return rows
.get(row
).get(column
).getText();
1424 * Set the text of a particular cell.
1426 * @param column the cell column
1427 * @param row the cell row
1428 * @param text the text to put into the cell
1430 public void setCellText(final int column
, final int row
,
1431 final String text
) {
1433 if ((column
< 0) || (column
> columns
.size() - 1)) {
1434 throw new IndexOutOfBoundsException("Column count is " +
1435 columns
.size() + ", requested index " + column
);
1437 if ((row
< 0) || (row
> rows
.size() - 1)) {
1438 throw new IndexOutOfBoundsException("Row count is " +
1439 rows
.size() + ", requested index " + row
);
1441 rows
.get(row
).get(column
).setText(text
);
1445 * Set the action to perform when the user presses enter on a particular
1448 * @param column the cell column
1449 * @param row the cell row
1450 * @param action the action to perform when the user presses enter on the
1453 public void setCellEnterAction(final int column
, final int row
,
1454 final TAction action
) {
1456 if ((column
< 0) || (column
> columns
.size() - 1)) {
1457 throw new IndexOutOfBoundsException("Column count is " +
1458 columns
.size() + ", requested index " + column
);
1460 if ((row
< 0) || (row
> rows
.size() - 1)) {
1461 throw new IndexOutOfBoundsException("Row count is " +
1462 rows
.size() + ", requested index " + row
);
1464 rows
.get(row
).get(column
).field
.setEnterAction(action
);
1468 * Set the action to perform when the user updates a particular cell.
1470 * @param column the cell column
1471 * @param row the cell row
1472 * @param action the action to perform when the user updates the cell
1474 public void setCellUpdateAction(final int column
, final int row
,
1475 final TAction action
) {
1477 if ((column
< 0) || (column
> columns
.size() - 1)) {
1478 throw new IndexOutOfBoundsException("Column count is " +
1479 columns
.size() + ", requested index " + column
);
1481 if ((row
< 0) || (row
> rows
.size() - 1)) {
1482 throw new IndexOutOfBoundsException("Row count is " +
1483 rows
.size() + ", requested index " + row
);
1485 rows
.get(row
).get(column
).field
.setUpdateAction(action
);
1489 * Get the width of a column.
1491 * @param column the column number
1492 * @return the width of the column
1494 public int getColumnWidth(final int column
) {
1495 if ((column
< 0) || (column
> columns
.size() - 1)) {
1496 throw new IndexOutOfBoundsException("Column count is " +
1497 columns
.size() + ", requested index " + column
);
1499 return columns
.get(column
).width
;
1503 * Set the width of a column.
1505 * @param column the column number
1506 * @param width the new width of the column
1508 public void setColumnWidth(final int column
, final int width
) {
1509 if ((column
< 0) || (column
> columns
.size() - 1)) {
1510 throw new IndexOutOfBoundsException("Column count is " +
1511 columns
.size() + ", requested index " + column
);
1515 // Columns may not be smaller than 4 cells wide.
1519 int delta
= width
- columns
.get(column
).width
;
1520 columns
.get(column
).width
= width
;
1521 for (Cell cell
: columns
.get(column
).cells
) {
1522 cell
.setWidth(columns
.get(column
).width
);
1523 cell
.field
.setWidth(columns
.get(column
).width
);
1525 for (int i
= column
+ 1; i
< columns
.size(); i
++) {
1526 columns
.get(i
).setX(columns
.get(i
).getX() + delta
);
1528 if (column
== columns
.size() - 1) {
1529 bottomRightCorner();
1536 * Get the label of a column.
1538 * @param column the column number
1539 * @return the label of the column
1541 public String
getColumnLabel(final int column
) {
1542 if ((column
< 0) || (column
> columns
.size() - 1)) {
1543 throw new IndexOutOfBoundsException("Column count is " +
1544 columns
.size() + ", requested index " + column
);
1546 return columns
.get(column
).label
;
1550 * Set the label of a column.
1552 * @param column the column number
1553 * @param label the new label of the column
1555 public void setColumnLabel(final int column
, final String label
) {
1556 if ((column
< 0) || (column
> columns
.size() - 1)) {
1557 throw new IndexOutOfBoundsException("Column count is " +
1558 columns
.size() + ", requested index " + column
);
1560 columns
.get(column
).label
= label
;
1564 * Get the label of a row.
1566 * @param row the row number
1567 * @return the label of the row
1569 public String
getRowLabel(final int row
) {
1570 if ((row
< 0) || (row
> rows
.size() - 1)) {
1571 throw new IndexOutOfBoundsException("Row count is " +
1572 rows
.size() + ", requested index " + row
);
1574 return rows
.get(row
).label
;
1578 * Set the label of a row.
1580 * @param row the row number
1581 * @param label the new label of the row
1583 public void setRowLabel(final int row
, final String label
) {
1584 if ((row
< 0) || (row
> rows
.size() - 1)) {
1585 throw new IndexOutOfBoundsException("Row count is " +
1586 rows
.size() + ", requested index " + row
);
1588 rows
.get(row
).label
= label
;
1592 * Insert one row at a particular index.
1594 * @param idx the row number
1596 private void insertRowAt(final int idx
) {
1597 Row newRow
= new Row(idx
);
1598 for (int i
= 0; i
< columns
.size(); i
++) {
1599 Cell cell
= new Cell(this, columns
.get(i
).getX(),
1600 rows
.get(selectedRow
).getY(), COLUMN_DEFAULT_WIDTH
, 1, i
, idx
);
1602 columns
.get(i
).cells
.add(idx
, cell
);
1604 rows
.add(idx
, newRow
);
1606 for (int x
= 0; x
< columns
.size(); x
++) {
1607 for (int y
= idx
; y
< rows
.size(); y
++) {
1608 columns
.get(x
).get(y
).row
= y
;
1609 columns
.get(x
).get(y
).column
= x
;
1612 for (int i
= idx
+ 1; i
< rows
.size(); i
++) {
1613 String oldRowLabel
= Integer
.toString(i
- 1);
1614 if (rows
.get(i
).label
.equals(oldRowLabel
)) {
1615 rows
.get(i
).label
= Integer
.toString(i
);
1622 * Insert one row above a particular row.
1624 * @param row the row number
1626 public void insertRowAbove(final int row
) {
1627 if ((row
< 0) || (row
> rows
.size() - 1)) {
1628 throw new IndexOutOfBoundsException("Row count is " +
1629 rows
.size() + ", requested index " + row
);
1631 insertRowAt(selectedRow
);
1633 activate(columns
.get(selectedColumn
).get(selectedRow
));
1637 * Insert one row below a particular row.
1639 * @param row the row number
1641 public void insertRowBelow(final int row
) {
1642 if ((row
< 0) || (row
> rows
.size() - 1)) {
1643 throw new IndexOutOfBoundsException("Row count is " +
1644 rows
.size() + ", requested index " + row
);
1646 int idx
= selectedRow
+ 1;
1647 if (idx
< rows
.size()) {
1649 activate(columns
.get(selectedColumn
).get(selectedRow
));
1653 // selectedRow is the last row, we need to perform an append.
1654 Row newRow
= new Row(idx
);
1655 for (int i
= 0; i
< columns
.size(); i
++) {
1656 Cell cell
= new Cell(this, columns
.get(i
).getX(),
1657 rows
.get(selectedRow
).getY(), COLUMN_DEFAULT_WIDTH
, 1, i
, idx
);
1659 columns
.get(i
).cells
.add(cell
);
1663 activate(columns
.get(selectedColumn
).get(selectedRow
));
1667 * Delete a particular row.
1669 * @param row the row number
1671 public void deleteRow(final int row
) {
1672 if ((row
< 0) || (row
> rows
.size() - 1)) {
1673 throw new IndexOutOfBoundsException("Row count is " +
1674 rows
.size() + ", requested index " + row
);
1676 if (rows
.size() == 1) {
1677 // Don't delete the last row.
1680 for (int i
= 0; i
< columns
.size(); i
++) {
1681 Cell cell
= columns
.get(i
).cells
.remove(row
);
1682 getChildren().remove(cell
);
1686 for (int x
= 0; x
< columns
.size(); x
++) {
1687 for (int y
= row
; y
< rows
.size(); y
++) {
1688 columns
.get(x
).get(y
).row
= y
;
1689 columns
.get(x
).get(y
).column
= x
;
1692 for (int i
= row
; i
< rows
.size(); i
++) {
1693 String oldRowLabel
= Integer
.toString(i
+ 1);
1694 if (rows
.get(i
).label
.equals(oldRowLabel
)) {
1695 rows
.get(i
).label
= Integer
.toString(i
);
1698 if (selectedRow
== rows
.size()) {
1701 activate(columns
.get(selectedColumn
).get(selectedRow
));
1702 bottomRightCorner();
1706 * Insert one column at a particular index.
1708 * @param idx the column number
1710 private void insertColumnAt(final int idx
) {
1711 Column newColumn
= new Column(idx
);
1712 for (int i
= 0; i
< rows
.size(); i
++) {
1713 Cell cell
= new Cell(this, columns
.get(selectedColumn
).getX(),
1714 rows
.get(i
).getY(), COLUMN_DEFAULT_WIDTH
, 1, idx
, i
);
1715 newColumn
.add(cell
);
1716 rows
.get(i
).cells
.add(idx
, cell
);
1718 columns
.add(idx
, newColumn
);
1720 for (int x
= idx
; x
< columns
.size(); x
++) {
1721 for (int y
= 0; y
< rows
.size(); y
++) {
1722 columns
.get(x
).get(y
).row
= y
;
1723 columns
.get(x
).get(y
).column
= x
;
1726 for (int i
= idx
+ 1; i
< columns
.size(); i
++) {
1727 String oldColumnLabel
= makeColumnLabel(i
- 1);
1728 if (columns
.get(i
).label
.equals(oldColumnLabel
)) {
1729 columns
.get(i
).label
= makeColumnLabel(i
);
1736 * Insert one column to the left of a particular column.
1738 * @param column the column number
1740 public void insertColumnLeft(final int column
) {
1741 if ((column
< 0) || (column
> columns
.size() - 1)) {
1742 throw new IndexOutOfBoundsException("Column count is " +
1743 columns
.size() + ", requested index " + column
);
1745 insertColumnAt(selectedColumn
);
1747 activate(columns
.get(selectedColumn
).get(selectedRow
));
1751 * Insert one column to the right of a particular column.
1753 * @param column the column number
1755 public void insertColumnRight(final int column
) {
1756 if ((column
< 0) || (column
> columns
.size() - 1)) {
1757 throw new IndexOutOfBoundsException("Column count is " +
1758 columns
.size() + ", requested index " + column
);
1760 int idx
= selectedColumn
+ 1;
1761 if (idx
< columns
.size()) {
1762 insertColumnAt(idx
);
1763 activate(columns
.get(selectedColumn
).get(selectedRow
));
1767 // selectedColumn is the last column, we need to perform an append.
1768 Column newColumn
= new Column(idx
);
1769 for (int i
= 0; i
< rows
.size(); i
++) {
1770 Cell cell
= new Cell(this, columns
.get(selectedColumn
).getX(),
1771 rows
.get(i
).getY(), COLUMN_DEFAULT_WIDTH
, 1, idx
, i
);
1772 newColumn
.add(cell
);
1773 rows
.get(i
).cells
.add(cell
);
1775 columns
.add(newColumn
);
1777 activate(columns
.get(selectedColumn
).get(selectedRow
));
1781 * Delete a particular column.
1783 * @param column the column number
1785 public void deleteColumn(final int column
) {
1786 if ((column
< 0) || (column
> columns
.size() - 1)) {
1787 throw new IndexOutOfBoundsException("Column count is " +
1788 columns
.size() + ", requested index " + column
);
1790 if (columns
.size() == 1) {
1791 // Don't delete the last column.
1794 for (int i
= 0; i
< rows
.size(); i
++) {
1795 Cell cell
= rows
.get(i
).cells
.remove(column
);
1796 getChildren().remove(cell
);
1798 columns
.remove(column
);
1800 for (int x
= column
; x
< columns
.size(); x
++) {
1801 for (int y
= 0; y
< rows
.size(); y
++) {
1802 columns
.get(x
).get(y
).row
= y
;
1803 columns
.get(x
).get(y
).column
= x
;
1806 for (int i
= column
; i
< columns
.size(); i
++) {
1807 String oldColumnLabel
= makeColumnLabel(i
+ 1);
1808 if (columns
.get(i
).label
.equals(oldColumnLabel
)) {
1809 columns
.get(i
).label
= makeColumnLabel(i
);
1812 if (selectedColumn
== columns
.size()) {
1815 activate(columns
.get(selectedColumn
).get(selectedRow
));
1816 bottomRightCorner();
1820 * Delete the selected cell, shifting cells over to the left.
1822 public void deleteCellShiftLeft() {
1823 // All we do is copy the text from every cell in this row over.
1824 for (int i
= selectedColumn
+ 1; i
< columns
.size(); i
++) {
1825 setCellText(i
- 1, selectedRow
, getCellText(i
, selectedRow
));
1827 setCellText(columns
.size() - 1, selectedRow
, "");
1831 * Delete the selected cell, shifting cells from below up.
1833 public void deleteCellShiftUp() {
1834 // All we do is copy the text from every cell in this column up.
1835 for (int i
= selectedRow
+ 1; i
< rows
.size(); i
++) {
1836 setCellText(selectedColumn
, i
- 1, getCellText(selectedColumn
, i
));
1838 setCellText(selectedColumn
, rows
.size() - 1, "");
1842 * Set a particular cell read-only (non-editable) or not.
1844 * @param column the cell column
1845 * @param row the cell row
1846 * @param readOnly if true, the cell will be non-editable
1848 public void setCellReadOnly(final int column
, final int row
,
1849 final boolean readOnly
) {
1851 if ((column
< 0) || (column
> columns
.size() - 1)) {
1852 throw new IndexOutOfBoundsException("Column count is " +
1853 columns
.size() + ", requested index " + column
);
1855 if ((row
< 0) || (row
> rows
.size() - 1)) {
1856 throw new IndexOutOfBoundsException("Row count is " +
1857 rows
.size() + ", requested index " + row
);
1859 rows
.get(row
).get(column
).setReadOnly(readOnly
);
1863 * Set an entire row of cells read-only (non-editable) or not.
1865 * @param row the row number
1866 * @param readOnly if true, the cells will be non-editable
1868 public void setRowReadOnly(final int row
, final boolean readOnly
) {
1869 if ((row
< 0) || (row
> rows
.size() - 1)) {
1870 throw new IndexOutOfBoundsException("Row count is " +
1871 rows
.size() + ", requested index " + row
);
1873 for (Cell cell
: rows
.get(row
).cells
) {
1874 cell
.setReadOnly(readOnly
);
1879 * Set an entire column of cells read-only (non-editable) or not.
1881 * @param column the column number
1882 * @param readOnly if true, the cells will be non-editable
1884 public void setColumnReadOnly(final int column
, final boolean readOnly
) {
1885 if ((column
< 0) || (column
> columns
.size() - 1)) {
1886 throw new IndexOutOfBoundsException("Column count is " +
1887 columns
.size() + ", requested index " + column
);
1889 for (Cell cell
: columns
.get(column
).cells
) {
1890 cell
.setReadOnly(readOnly
);
1895 * Set all borders across the entire table to Border.NONE.
1897 public void setBorderAllNone() {
1898 topBorder
= Border
.NONE
;
1899 leftBorder
= Border
.NONE
;
1900 for (int i
= 0; i
< columns
.size(); i
++) {
1901 columns
.get(i
).rightBorder
= Border
.NONE
;
1903 for (int i
= 0; i
< rows
.size(); i
++) {
1904 rows
.get(i
).bottomBorder
= Border
.NONE
;
1905 rows
.get(i
).height
= 1;
1907 bottomRightCorner();
1911 * Set all borders across the entire table to Border.SINGLE.
1913 public void setBorderAllSingle() {
1914 topBorder
= Border
.SINGLE
;
1915 leftBorder
= Border
.SINGLE
;
1916 for (int i
= 0; i
< columns
.size(); i
++) {
1917 columns
.get(i
).rightBorder
= Border
.SINGLE
;
1919 for (int i
= 0; i
< rows
.size(); i
++) {
1920 rows
.get(i
).bottomBorder
= Border
.SINGLE
;
1921 rows
.get(i
).height
= 2;
1927 * Set all borders around the selected cell to Border.NONE.
1929 public void setBorderCellNone() {
1930 if (selectedRow
== 0) {
1931 topBorder
= Border
.NONE
;
1933 if (selectedColumn
== 0) {
1934 leftBorder
= Border
.NONE
;
1936 columns
.get(selectedColumn
).rightBorder
= Border
.NONE
;
1937 rows
.get(selectedRow
).bottomBorder
= Border
.NONE
;
1938 rows
.get(selectedRow
).height
= 1;
1939 bottomRightCorner();
1943 * Set all borders around the selected cell to Border.SINGLE.
1945 public void setBorderCellSingle() {
1946 if (selectedRow
== 0) {
1947 topBorder
= Border
.SINGLE
;
1949 if (selectedColumn
== 0) {
1950 leftBorder
= Border
.SINGLE
;
1952 columns
.get(selectedColumn
).rightBorder
= Border
.SINGLE
;
1953 rows
.get(selectedRow
).bottomBorder
= Border
.SINGLE
;
1954 rows
.get(selectedRow
).height
= 2;
1959 * Set the column border to the right of the selected cell to
1962 public void setBorderColumnRightSingle() {
1963 columns
.get(selectedColumn
).rightBorder
= Border
.SINGLE
;
1968 * Set the column border to the right of the selected cell to
1971 public void setBorderColumnLeftSingle() {
1972 if (selectedColumn
== 0) {
1973 leftBorder
= Border
.SINGLE
;
1975 columns
.get(selectedColumn
- 1).rightBorder
= Border
.SINGLE
;
1981 * Set the row border above the selected cell to Border.SINGLE.
1983 public void setBorderRowAboveSingle() {
1984 if (selectedRow
== 0) {
1985 topBorder
= Border
.SINGLE
;
1987 rows
.get(selectedRow
- 1).bottomBorder
= Border
.SINGLE
;
1988 rows
.get(selectedRow
- 1).height
= 2;
1994 * Set the row border below the selected cell to Border.SINGLE.
1996 public void setBorderRowBelowSingle() {
1997 rows
.get(selectedRow
).bottomBorder
= Border
.SINGLE
;
1998 rows
.get(selectedRow
).height
= 2;
2003 * Set the row border below the selected cell to Border.DOUBLE.
2005 public void setBorderRowBelowDouble() {
2006 rows
.get(selectedRow
).bottomBorder
= Border
.DOUBLE
;
2007 rows
.get(selectedRow
).height
= 2;
2012 * Set the row border below the selected cell to Border.THICK.
2014 public void setBorderRowBelowThick() {
2015 rows
.get(selectedRow
).bottomBorder
= Border
.THICK
;
2016 rows
.get(selectedRow
).height
= 2;