X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTTableWidget.java;h=2e10a3faedc702295335cd740d60a85ca4a331e6;hb=28c0cfa6a54efb01308855e0528a86a528e987b6;hp=1107a4e684bdb09dc7f7a203a220b11374a15408;hpb=68ee64d06f760a74b24e0a0cc9b47a160daeec75;p=fanfix.git diff --git a/src/jexer/TTableWidget.java b/src/jexer/TTableWidget.java index 1107a4e..2e10a3f 100644 --- a/src/jexer/TTableWidget.java +++ b/src/jexer/TTableWidget.java @@ -28,12 +28,15 @@ */ package jexer; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import jexer.bits.CellAttributes; import jexer.event.TKeypressEvent; import jexer.event.TMenuEvent; +import jexer.event.TMouseEvent; +import jexer.event.TResizeEvent; import jexer.menu.TMenu; import static jexer.TKeypress.*; @@ -308,7 +311,7 @@ public class TTableWidget extends TWidget { this.column = column; this.row = row; - field = addField(0, 0, width - 1, false); + field = addField(0, 0, width, false); field.setEnabled(false); field.setBackgroundChar(' '); } @@ -317,6 +320,66 @@ public class TTableWidget extends TWidget { // Event handlers ----------------------------------------------------- // -------------------------------------------------------------------- + /** + * Handle mouse double-click events. + * + * @param mouse mouse double-click event + */ + @Override + public void onMouseDoubleClick(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + // Double-click means to start editing. + fieldText = field.getText(); + isEditing = true; + field.setEnabled(true); + activate(field); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(); + } + } + + /** + * Handle mouse press events. + * + * @param mouse mouse button press event + */ + @Override + public void onMouseDown(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(); + } + } + + /** + * Handle mouse release events. + * + * @param mouse mouse button release event + */ + @Override + public void onMouseUp(final TMouseEvent mouse) { + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + + if (isActive()) { + // Let the table know that I was activated. + ((TTableWidget) getParent()).selectedRow = row; + ((TTableWidget) getParent()).selectedColumn = column; + ((TTableWidget) getParent()).alignGrid(); + } + } + /** * Handle keystrokes. * @@ -388,6 +451,8 @@ public class TTableWidget extends TWidget { field.setInactiveColorKey("ttable.inactive"); } + assert (isVisible() == true); + super.draw(); } @@ -461,12 +526,49 @@ public class TTableWidget extends TWidget { activate(columns.get(selectedColumn).get(selectedRow)); alignGrid(); + + // Set the menu to match the flags. + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS). + setChecked(showRowLabels); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS). + setChecked(showColumnLabels); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW). + setChecked(highlightRow); + getApplication().getMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN). + setChecked(highlightColumn); + + } // ------------------------------------------------------------------------ // Event handlers --------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Handle mouse press events. + * + * @param mouse mouse button press event + */ + @Override + public void onMouseDown(final TMouseEvent mouse) { + if (mouse.isMouseWheelUp() || mouse.isMouseWheelDown()) { + // Treat wheel up/down as 3 up/down + TKeypressEvent keyEvent; + if (mouse.isMouseWheelUp()) { + keyEvent = new TKeypressEvent(kbUp); + } else { + keyEvent = new TKeypressEvent(kbDown); + } + for (int i = 0; i < 3; i++) { + onKeypress(keyEvent); + } + return; + } + + // Use TWidget's code to pass the event to the children. + super.onMouseDown(mouse); + } + /** * Handle keystrokes. * @@ -489,39 +591,65 @@ public class TTableWidget extends TWidget { } if (keypress.equals(kbLeft)) { + // Left if (selectedColumn > 0) { selectedColumn--; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbRight)) { + // Right if (selectedColumn < columns.size() - 1) { selectedColumn++; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbUp)) { + // Up if (selectedRow > 0) { selectedRow--; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbDown)) { + // Down if (selectedRow < rows.size() - 1) { selectedRow++; } activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbHome)) { + // Home - leftmost column selectedColumn = 0; activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbEnd)) { + // End - rightmost column selectedColumn = columns.size() - 1; activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbPgUp)) { - // TODO + // PgUp - Treat like multiple up + for (int i = 0; i < getHeight() - 2; i++) { + if (selectedRow > 0) { + selectedRow--; + } + } + activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbPgDn)) { - // TODO + // PgDn - Treat like multiple up + for (int i = 0; i < getHeight() - 2; i++) { + if (selectedRow < rows.size() - 1) { + selectedRow++; + } + } + activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbCtrlHome)) { - // TODO + // Ctrl-Home - go to top-left + selectedRow = 0; + selectedColumn = 0; + activate(columns.get(selectedColumn).get(selectedRow)); + activate(columns.get(selectedColumn).get(selectedRow)); } else if (keypress.equals(kbCtrlEnd)) { - // TODO + // Ctrl-End - go to bottom-right + selectedRow = rows.size() - 1; + selectedColumn = columns.size() - 1; + activate(columns.get(selectedColumn).get(selectedRow)); + activate(columns.get(selectedColumn).get(selectedRow)); } else { // Pass to the Cell. super.onKeypress(keypress); @@ -532,6 +660,18 @@ public class TTableWidget extends TWidget { alignGrid(); } + /** + * Handle widget resize events. + * + * @param event resize event + */ + @Override + public void onResize(final TResizeEvent event) { + super.onResize(event); + + alignGrid(); + } + /** * Handle posted menu events. * @@ -540,6 +680,18 @@ public class TTableWidget extends TWidget { @Override public void onMenu(final TMenuEvent menu) { switch (menu.getId()) { + case TMenu.MID_TABLE_VIEW_ROW_LABELS: + showRowLabels = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_COLUMN_LABELS: + showColumnLabels = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW: + highlightRow = getApplication().getMenuItem(menu.getId()).getChecked(); + break; + case TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN: + highlightColumn = getApplication().getMenuItem(menu.getId()).getChecked(); + break; case TMenu.MID_TABLE_BORDER_NONE: case TMenu.MID_TABLE_BORDER_ALL: case TMenu.MID_TABLE_BORDER_RIGHT: @@ -561,7 +713,7 @@ public class TTableWidget extends TWidget { columns.get(selectedColumn).width--; for (Cell cell: getSelectedColumn().cells) { cell.setWidth(columns.get(selectedColumn).width); - cell.field.setWidth(columns.get(selectedColumn).width - 1); + cell.field.setWidth(columns.get(selectedColumn).width); } for (int i = selectedColumn + 1; i < columns.size(); i++) { for (Cell cell: columns.get(i).cells) { @@ -574,7 +726,7 @@ public class TTableWidget extends TWidget { columns.get(selectedColumn).width++; for (Cell cell: getSelectedColumn().cells) { cell.setWidth(columns.get(selectedColumn).width); - cell.field.setWidth(columns.get(selectedColumn).width - 1); + cell.field.setWidth(columns.get(selectedColumn).width); } for (int i = selectedColumn + 1; i < columns.size(); i++) { for (Cell cell: columns.get(i).cells) { @@ -584,11 +736,16 @@ public class TTableWidget extends TWidget { alignGrid(); break; case TMenu.MID_TABLE_FILE_SAVE_CSV: + // TODO + break; case TMenu.MID_TABLE_FILE_SAVE_TEXT: + // TODO break; default: super.onMenu(menu); } + + alignGrid(); } // ------------------------------------------------------------------------ @@ -596,34 +753,37 @@ public class TTableWidget extends TWidget { // ------------------------------------------------------------------------ /** - * Draw the table row/column headings, and borders. + * Draw the table row/column labels, and borders. */ @Override public void draw() { - CellAttributes headingColor = getTheme().getColor("ttable.heading"); + CellAttributes labelColor = getTheme().getColor("ttable.label"); + CellAttributes labelColorSelected = getTheme().getColor("ttable.label.selected"); CellAttributes borderColor = getTheme().getColor("ttable.border"); // Column labels. if (showColumnLabels == true) { - int x = 0; - if (showRowLabels == true) { - x += 8; - } for (int i = left; i < columns.size(); i++) { - putStringXY(x + (i * 8), 0, String.format(" %-6s ", - columns.get(i).label), headingColor); + if (columns.get(i).get(top).isVisible() == false) { + break; + } + putStringXY(columns.get(i).get(top).getX(), 0, + String.format(" %-" + + (columns.get(i).get(top).getWidth() - 2) + + "s ", columns.get(i).label), + (i == selectedColumn ? labelColorSelected : labelColor)); } } // Row labels. if (showRowLabels == true) { - int y = 0; - if (showColumnLabels == true) { - y++; - } for (int i = top; i < rows.size(); i++) { - putStringXY(0, y + i, String.format(" %-6s ", - rows.get(i).label), headingColor); + 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)); } } @@ -675,12 +835,78 @@ public class TTableWidget extends TWidget { 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 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(); + } + /** * Get the full horizontal width of this table. * * @return the width required to render the entire table */ - public int getMaximumWidth() { + private int getMaximumWidth() { int totalWidth = 0; if (showRowLabels == true) { // For now, all row labels are 8 cells wide. TODO: make this @@ -698,7 +924,7 @@ public class TTableWidget extends TWidget { * * @return the height required to render the entire table */ - public int getMaximumHeight() { + private int getMaximumHeight() { int totalHeight = 0; if (showColumnLabels == true) { // For now, all column labels are 1 cell tall. TODO: make this @@ -717,10 +943,29 @@ public class TTableWidget extends TWidget { */ private void alignGrid() { + /* + * We start by assuming that all cells are visible, and then mark as + * invisible those that are outside the viewable area. + */ + for (int x = 0; x < columns.size(); x++) { + for (int y = 0; y < rows.size(); y++) { + Cell cell = rows.get(y).cells.get(x); + cell.setVisible(true); + + // Special case: mouse double-clicks can lead to multiple + // cells in editing mode. Only allow a cell to remain + // editing if it is fact the active widget. + if (cell.isEditing && !cell.isActive()) { + cell.fieldText = cell.field.getText(); + cell.isEditing = false; + cell.field.setEnabled(false); + } + } + } + // Adjust X locations to be visible ----------------------------------- // Determine if we need to shift left or right. - int width = getMaximumWidth(); int leftCellX = 0; if (showRowLabels == true) { // For now, all row labels are 8 cells wide. TODO: make this @@ -739,18 +984,23 @@ public class TTableWidget extends TWidget { // There should always be a selected column. assert (selectedColumnCell != null); - while (leftCellX + selectedColumnCell.getWidth() + 1 > getWidth()) { - leftCellX -= (getWidth() - selectedColumnCell.getWidth() - 1); + int excessWidth = leftCellX + selectedColumnCell.getWidth() + 1 - getWidth(); + if (excessWidth > 0) { + leftCellX -= excessWidth; } if (leftCellX < 0) { - leftCellX = 0; + if (showRowLabels == true) { + leftCellX = 8; + } else { + leftCellX = 0; + } } /* * leftCellX now contains the basic left offset necessary to draw the * cells such that the selected cell (column) is fully visible within * this widget's given width. Or, if the widget is too narrow to - * display the full cell, leftCellX is 0. + * display the full cell, leftCellX is 0 or 8. * * Now reset all of the X positions of the other cells so that the * selected cell X is leftCellX. @@ -760,8 +1010,8 @@ public class TTableWidget extends TWidget { int newCellX = leftCellX; left = selectedColumn; for (int x = selectedColumn - 1; x >= 0; x--) { - newCellX -= rows.get(y).cells.get(x).getWidth() - 1; - if (newCellX - rows.get(y).cells.get(x).getWidth() - 1 > 0) { + newCellX -= rows.get(y).cells.get(x).getWidth() + 1; + if (newCellX >= (showRowLabels ? 8 : 0)) { rows.get(y).cells.get(x).setVisible(true); rows.get(y).cells.get(x).setX(newCellX); left--; @@ -773,11 +1023,12 @@ public class TTableWidget extends TWidget { // Selected cell. rows.get(y).cells.get(selectedColumn).setX(leftCellX); + assert (rows.get(y).cells.get(selectedColumn).isVisible()); // All cells to the right of selected cell. newCellX = leftCellX + selectedColumnCell.getWidth() + 1; for (int x = selectedColumn + 1; x < columns.size(); x++) { - if (newCellX < getWidth()) { + if (newCellX <= getWidth()) { rows.get(y).cells.get(x).setVisible(true); rows.get(y).cells.get(x).setX(newCellX); } else { @@ -792,7 +1043,6 @@ public class TTableWidget extends TWidget { // The same logic as above, but applied to the column Y. // Determine if we need to shift up or down. - int height = getMaximumHeight(); int topCellY = 0; if (showColumnLabels == true) { // For now, all column labels are 1 cell high. TODO: make this @@ -812,29 +1062,44 @@ public class TTableWidget extends TWidget { // There should always be a selected row. assert (selectedRowCell != null); - while (topCellY + selectedRowCell.getHeight() > getHeight()) { - topCellY -= (getHeight() - selectedRowCell.getHeight()); + int excessHeight = topCellY + selectedRowCell.getHeight() - getHeight() - 1; + if (showColumnLabels == true) { + excessHeight += 1; + } + if (excessHeight > 0) { + topCellY -= excessHeight; } if (topCellY < 0) { - topCellY = 0; + if (showColumnLabels == true) { + topCellY = 1; + } else { + topCellY = 0; + } } /* * topCellY now contains the basic top offset necessary to draw the * cells such that the selected cell (row) is fully visible within * this widget's given height. Or, if the widget is too short to - * display the full cell, topCellY is 0. + * display the full cell, topCellY is 0 or 1. * * Now reset all of the Y positions of the other cells so that the * selected cell Y is topCellY. */ for (int x = 0; x < columns.size(); x++) { + + if (columns.get(x).get(0).isVisible() == false) { + // This column won't be visible as determined by the checks + // above, just continue to the next. + continue; + } + // All cells above the selected cell. int newCellY = topCellY; top = selectedRow; for (int y = selectedRow - 1; y >= 0; y--) { newCellY -= rows.get(y).cells.get(x).getHeight(); - if (newCellY - rows.get(y).cells.get(x).getHeight() > 0) { + if (newCellY >= (showColumnLabels == true ? 1 : 0)) { rows.get(y).cells.get(x).setVisible(true); rows.get(y).cells.get(x).setY(newCellY); top--; @@ -845,12 +1110,12 @@ public class TTableWidget extends TWidget { } // Selected cell. - columns.get(x).cells.get(selectedColumn).setY(topCellY); + columns.get(x).cells.get(selectedRow).setY(topCellY); - // All cells below of selected cell. + // All cells below the selected cell. newCellY = topCellY + selectedRowCell.getHeight(); for (int y = selectedRow + 1; y < rows.size(); y++) { - if (newCellY < getHeight()) { + if (newCellY <= getHeight()) { rows.get(y).cells.get(x).setVisible(true); rows.get(y).cells.get(x).setY(newCellY); } else { @@ -863,4 +1128,14 @@ public class TTableWidget extends TWidget { } + /** + * Save contents to file. + * + * @param filename file to save to + * @throws IOException if a java.io operation throws + */ + public void saveToFilename(final String filename) throws IOException { + // TODO + } + }