# Generated docs
docs/**
+# Maven artifacts
+target/**
+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
import jexer.backend.TWindowBackend;
import jexer.menu.TMenu;
import jexer.menu.TMenuItem;
+import jexer.menu.TSubMenu;
import static jexer.TCommand.*;
import static jexer.TKeypress.*;
return helpMenu;
}
+ /**
+ * Convenience function to add a default "Table" menu.
+ *
+ * @return the new menu
+ */
+ public final TMenu addTableMenu() {
+ TMenu tableMenu = addMenu(i18n.getString("tableMenuTitle"));
+ TSubMenu borderMenu = tableMenu.addSubMenu(i18n.
+ getString("tableSubMenuBorders"));
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_NONE, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_ALL, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_RIGHT, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_LEFT, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_TOP, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_BOTTOM, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM, false);
+ borderMenu.addDefaultItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM, false);
+ TSubMenu deleteMenu = tableMenu.addSubMenu(i18n.
+ getString("tableSubMenuDelete"));
+ deleteMenu.addDefaultItem(TMenu.MID_TABLE_DELETE_LEFT, false);
+ deleteMenu.addDefaultItem(TMenu.MID_TABLE_DELETE_UP, false);
+ deleteMenu.addDefaultItem(TMenu.MID_TABLE_DELETE_ROW, false);
+ deleteMenu.addDefaultItem(TMenu.MID_TABLE_DELETE_COLUMN, false);
+ TSubMenu insertMenu = tableMenu.addSubMenu(i18n.
+ getString("tableSubMenuInsert"));
+ insertMenu.addDefaultItem(TMenu.MID_TABLE_INSERT_LEFT, false);
+ insertMenu.addDefaultItem(TMenu.MID_TABLE_INSERT_RIGHT, false);
+ insertMenu.addDefaultItem(TMenu.MID_TABLE_INSERT_ABOVE, false);
+ insertMenu.addDefaultItem(TMenu.MID_TABLE_INSERT_BELOW, false);
+ TSubMenu columnMenu = tableMenu.addSubMenu(i18n.
+ getString("tableSubMenuColumn"));
+ columnMenu.addDefaultItem(TMenu.MID_TABLE_COLUMN_NARROW, false);
+ columnMenu.addDefaultItem(TMenu.MID_TABLE_COLUMN_WIDEN, false);
+ TSubMenu fileMenu = tableMenu.addSubMenu(i18n.
+ getString("tableSubMenuFile"));
+ fileMenu.addDefaultItem(TMenu.MID_TABLE_FILE_SAVE_CSV, false);
+ fileMenu.addDefaultItem(TMenu.MID_TABLE_FILE_SAVE_TEXT, false);
+
+ TStatusBar statusBar = tableMenu.newStatusBar(i18n.
+ getString("tableMenuStatus"));
+ statusBar.addShortcutKeypress(kbF1, cmHelp, i18n.getString("Help"));
+ return tableMenu;
+ }
+
// ------------------------------------------------------------------------
// TTimer management ------------------------------------------------------
// ------------------------------------------------------------------------
helpMenuTitle=&Help
helpMenuStatus=Access online help
+tableMenuTitle=&Table
+tableSubMenuBorders=&Borders
+tableSubMenuDelete=&Delete
+tableSubMenuInsert=&Insert
+tableSubMenuColumn=&Column
+tableSubMenuFile=&File
+tableMenuStatus=Table manipulation commands
+
exitDialogTitle=Confirmation
exitDialogText=Exit application?
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
+ /**
+ * Background character for unfilled-in text.
+ */
+ protected char backgroundChar = GraphicsChars.HATCH;
+
/**
* Field text.
*/
*/
protected TAction updateAction;
+ /**
+ * The color to use when this field is active.
+ */
+ private String activeColorKey = "tfield.active";
+
+ /**
+ * The color to use when this field is not active.
+ */
+ private String inactiveColorKey = "tfield.inactive";
+
// ------------------------------------------------------------------------
// Constructors -----------------------------------------------------------
// ------------------------------------------------------------------------
CellAttributes fieldColor;
if (isAbsoluteActive()) {
- fieldColor = getTheme().getColor("tfield.active");
+ fieldColor = getTheme().getColor(activeColorKey);
} else {
- fieldColor = getTheme().getColor("tfield.inactive");
+ fieldColor = getTheme().getColor(inactiveColorKey);
}
int end = windowStart + getWidth();
if (end > text.length()) {
end = text.length();
}
- hLineXY(0, 0, getWidth(), GraphicsChars.HATCH, fieldColor);
+ hLineXY(0, 0, getWidth(), backgroundChar, fieldColor);
putStringXY(0, 0, text.substring(windowStart, end), fieldColor);
// Fix the cursor, it will be rendered by TApplication.drawAll().
// TField -----------------------------------------------------------------
// ------------------------------------------------------------------------
+ /**
+ * Get field background character.
+ *
+ * @return background character
+ */
+ public final char getBackgroundChar() {
+ return backgroundChar;
+ }
+
+ /**
+ * Set field background character.
+ *
+ * @param backgroundChar the background character
+ */
+ public void setBackgroundChar(final char backgroundChar) {
+ this.backgroundChar = backgroundChar;
+ }
+
/**
* Get field text.
*
normalizeWindowStart();
}
+ /**
+ * Set the active color key.
+ *
+ * @param activeColorKey ColorTheme key color to use when this field is
+ * active
+ */
+ public void setActiveColorKey(final String activeColorKey) {
+ this.activeColorKey = activeColorKey;
+ }
+
+ /**
+ * Set the inactive color key.
+ *
+ * @param inactiveColorKey ColorTheme key color to use when this field is
+ * inactive
+ */
+ public void setInactiveColorKey(final String inactiveColorKey) {
+ this.inactiveColorKey = inactiveColorKey;
+ }
+
+
}
return "\u25C0\u2500\u2518";
}
+ if (equals(kbShiftLeft)) {
+ return "Shift+\u2190";
+ }
+ if (equals(kbShiftRight)) {
+ return "Shift+\u2192";
+ }
+
if (isFunctionKey) {
switch (keyCode) {
case F1:
mnemonic = new MnemonicString(label);
}
+ /**
+ * Get the label color.
+ *
+ * @param return the ColorTheme key color to use for foreground text
+ */
+ public String getColorKey() {
+ return colorKey;
+ }
+
+ /**
+ * Set the label color.
+ *
+ * @param colorKey ColorTheme key color to use for foreground text
+ */
+ public void setColorKey(final String colorKey) {
+ this.colorKey = colorKey;
+ }
+
/**
* Act as though the mnemonic shortcut was pressed.
*/
end = text.length();
}
- hLineXY(0, 0, getWidth(), GraphicsChars.HATCH, fieldColor);
+ hLineXY(0, 0, getWidth(), backgroundChar, fieldColor);
if (showStars) {
hLineXY(0, 0, getWidth() - 2, '*', fieldColor);
} else {
--- /dev/null
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import jexer.event.TKeypressEvent;
+import jexer.event.TMenuEvent;
+import jexer.menu.TMenu;
+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: \u258C (vertical, left half block) and \u2580
+ * (horizontal, upper block).
+ */
+ THICK,
+ }
+
+ // ------------------------------------------------------------------------
+ // Variables --------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * The underlying data, organized as columns.
+ */
+ private ArrayList<Column> columns = new ArrayList<Column>();
+
+ /**
+ * The underlying data, organized as rows.
+ */
+ private ArrayList<Row> rows = new ArrayList<Row>();
+
+ /**
+ * 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;
+
+ /**
+ * Column represents a column of cells.
+ */
+ public class Column {
+
+ /**
+ * Width of column.
+ */
+ private int width = 8;
+
+ /**
+ * The cells of this column.
+ */
+ private ArrayList<Cell> cells = new ArrayList<Cell>();
+
+ /**
+ * Column label.
+ */
+ private String label = "";
+
+ /**
+ * The border for this column.
+ */
+ private Border border = Border.NONE;
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Row represents a row of cells.
+ */
+ public class Row {
+
+ /**
+ * Height of row.
+ */
+ private int height = 1;
+
+ /**
+ * The cells of this row.
+ */
+ private ArrayList<Cell> cells = new ArrayList<Cell>();
+
+ /**
+ * Row label.
+ */
+ private String label = "";
+
+ /**
+ * The border for this row.
+ */
+ private Border border = Border.NONE;
+
+ /**
+ * 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);
+ }
+
+ }
+
+ /**
+ * 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;
+
+ /**
+ * 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 - 1, false);
+ field.setEnabled(false);
+ field.setActiveColorKey("ttable.active");
+ field.setInactiveColorKey("ttable.inactive");
+ field.setBackgroundChar(' ');
+ }
+
+ // --------------------------------------------------------------------
+ // Event handlers -----------------------------------------------------
+ // --------------------------------------------------------------------
+
+ /**
+ * Handle keystrokes.
+ *
+ * @param keypress keystroke event
+ */
+ @Override
+ public void onKeypress(final TKeypressEvent keypress) {
+ // System.err.println("Cell onKeypress: " + keypress);
+
+ if (isEditing) {
+ if (keypress.equals(kbEsc)) {
+ // ESC cancels the edit.
+ field.setText(fieldText);
+ isEditing = false;
+ field.setEnabled(false);
+ return;
+ }
+ if (keypress.equals(kbEnter)) {
+ // Enter ends editing.
+ 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();
+
+ field.setActiveColorKey("ttable.active");
+ field.setInactiveColorKey("ttable.inactive");
+
+ if (isAbsoluteActive()) {
+ if (table.selectedColumn == column) {
+ if ((table.selectedRow == row)
+ || (table.highlightColumn == true)
+ ) {
+ field.setActiveColorKey("ttable.active");
+ field.setInactiveColorKey("ttable.active");
+ }
+ } else if (table.selectedRow == row) {
+ if ((table.selectedColumn == column)
+ || (table.highlightRow == true)
+ ) {
+ field.setActiveColorKey("ttable.active");
+ field.setInactiveColorKey("ttable.active");
+ }
+ }
+ }
+
+ 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);
+ }
+
+ }
+
+ // ------------------------------------------------------------------------
+ // 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
+ */
+ public TTableWidget(final TWidget parent, final int x, final int y,
+ final int width, final int height) {
+
+ super(parent, x, y, width, height);
+
+ // Initialize the starting row and column.
+ rows.add(new Row());
+ columns.add(new Column());
+
+ // Place a grid of cells that fit in this space.
+ int row = 0;
+ for (int i = 0; i < height; i += rows.get(0).height) {
+ int column = 0;
+ for (int j = 0; j < width; j += columns.get(0).width) {
+ Cell cell = new Cell(this, j, i, columns.get(0).width,
+ rows.get(0).height, column, row);
+
+ cell.setText("" + row + " " + column);
+ rows.get(row).add(cell);
+ columns.get(column).add(cell);
+ if ((i == 0) && (j + columns.get(0).width < width)) {
+ columns.add(new Column());
+ }
+ column++;
+ }
+ if (i + rows.get(0).height < height) {
+ rows.add(new Row());
+ }
+ row++;
+ }
+ activate(columns.get(selectedColumn).get(selectedRow));
+ }
+
+ // ------------------------------------------------------------------------
+ // Event handlers ---------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * 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 (getSelectedCell().isEditing) {
+ super.onKeypress(keypress);
+ return;
+ }
+
+ if (keypress.equals(kbLeft)) {
+ if (selectedColumn > 0) {
+ selectedColumn--;
+ }
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbRight)) {
+ if (selectedColumn < columns.size() - 1) {
+ selectedColumn++;
+ }
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbUp)) {
+ if (selectedRow > 0) {
+ selectedRow--;
+ }
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbDown)) {
+ if (selectedRow < rows.size() - 1) {
+ selectedRow++;
+ }
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbHome)) {
+ selectedColumn = 0;
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbEnd)) {
+ selectedColumn = columns.size() - 1;
+ activate(columns.get(selectedColumn).get(selectedRow));
+ } else if (keypress.equals(kbPgUp)) {
+ // TODO
+ } else if (keypress.equals(kbPgDn)) {
+ // TODO
+ } else if (keypress.equals(kbCtrlHome)) {
+ // TODO
+ } else if (keypress.equals(kbCtrlEnd)) {
+ // TODO
+ } else {
+ // Pass to the Cell.
+ super.onKeypress(keypress);
+ }
+ }
+
+ /**
+ * Handle posted menu events.
+ *
+ * @param menu menu event
+ */
+ @Override
+ public void onMenu(final TMenuEvent menu) {
+ switch (menu.getId()) {
+ case TMenu.MID_TABLE_BORDER_NONE:
+ case TMenu.MID_TABLE_BORDER_ALL:
+ case TMenu.MID_TABLE_BORDER_RIGHT:
+ case TMenu.MID_TABLE_BORDER_LEFT:
+ case TMenu.MID_TABLE_BORDER_TOP:
+ case TMenu.MID_TABLE_BORDER_BOTTOM:
+ case TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM:
+ case TMenu.MID_TABLE_BORDER_THICK_BOTTOM:
+ case TMenu.MID_TABLE_DELETE_LEFT:
+ case TMenu.MID_TABLE_DELETE_UP:
+ case TMenu.MID_TABLE_DELETE_ROW:
+ case TMenu.MID_TABLE_DELETE_COLUMN:
+ case TMenu.MID_TABLE_INSERT_LEFT:
+ case TMenu.MID_TABLE_INSERT_RIGHT:
+ case TMenu.MID_TABLE_INSERT_ABOVE:
+ case TMenu.MID_TABLE_INSERT_BELOW:
+ break;
+ case TMenu.MID_TABLE_COLUMN_NARROW:
+ columns.get(selectedColumn).width--;
+ for (Cell cell: getSelectedColumn().cells) {
+ cell.setWidth(columns.get(selectedColumn).width);
+ cell.field.setWidth(columns.get(selectedColumn).width - 1);
+ }
+ break;
+ case TMenu.MID_TABLE_COLUMN_WIDEN:
+ columns.get(selectedColumn).width++;
+ for (Cell cell: getSelectedColumn().cells) {
+ cell.setWidth(columns.get(selectedColumn).width);
+ cell.field.setWidth(columns.get(selectedColumn).width - 1);
+ }
+ break;
+ case TMenu.MID_TABLE_FILE_SAVE_CSV:
+ case TMenu.MID_TABLE_FILE_SAVE_TEXT:
+ break;
+ default:
+ super.onMenu(menu);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // TWidget ----------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ // ------------------------------------------------------------------------
+ // TTable -----------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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.util.ResourceBundle;
+
+import jexer.event.TCommandEvent;
+import jexer.event.TKeypressEvent;
+import jexer.event.TMouseEvent;
+import jexer.event.TResizeEvent;
+import jexer.menu.TMenu;
+import static jexer.TCommand.*;
+import static jexer.TKeypress.*;
+
+/**
+ * TTableWindow is used to display and edit regular two-dimensional tables of
+ * cells.
+ */
+public class TTableWindow extends TScrollableWindow {
+
+ /**
+ * Translated strings.
+ */
+ private static final ResourceBundle i18n = ResourceBundle.getBundle(TTableWindow.class.getName());
+
+ // ------------------------------------------------------------------------
+ // Variables --------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * The table widget.
+ */
+ private TTableWidget tableField;
+
+ // ------------------------------------------------------------------------
+ // Constructors -----------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Public constructor sets window title.
+ *
+ * @param parent the main application
+ * @param title the window title
+ */
+ public TTableWindow(final TApplication parent, final String title) {
+
+ super(parent, title, 0, 0, parent.getScreen().getWidth() / 2,
+ parent.getScreen().getHeight() / 2 - 2, RESIZABLE | CENTERED);
+
+ tableField = new TTableWidget(this, 0, 0, getWidth() - 2, getHeight() - 2);
+ setupAfterTable();
+ }
+
+ // ------------------------------------------------------------------------
+ // Event handlers ---------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Called by application.switchWindow() when this window gets the
+ * focus, and also by application.addWindow().
+ */
+ public void onFocus() {
+ // Enable the table menu items.
+ getApplication().enableMenuItem(TMenu.MID_CUT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_UP);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
+ getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
+ }
+
+ /**
+ * Called by application.switchWindow() when another window gets the
+ * focus.
+ */
+ public void onUnfocus() {
+ // Disable the table menu items.
+ getApplication().disableMenuItem(TMenu.MID_CUT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_UP);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
+ getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
+ }
+
+ // ------------------------------------------------------------------------
+ // TWindow ----------------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Draw the window.
+ */
+ @Override
+ public void draw() {
+ // Draw as normal.
+ super.draw();
+
+ // Add borders on rows and columns.
+ // TODO
+ }
+
+ /**
+ * 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 (mouseOnTable(mouse)) {
+ // The table might have changed, update the scollbars.
+ // TODO
+ /*
+ setBottomValue(editField.getMaximumRowNumber());
+ setVerticalValue(editField.getVisibleRowNumber());
+ setRightValue(editField.getMaximumColumnNumber());
+ setHorizontalValue(editField.getEditingColumnNumber());
+ */
+ } else {
+ if (mouse.isMouseWheelUp() || mouse.isMouseWheelDown()) {
+ // Vertical scrollbar actions
+ // TODO
+ // editField.setVisibleRowNumber(getVerticalValue());
+ }
+ }
+ }
+
+ /**
+ * 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.onMouseUp(mouse);
+
+ if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
+ // Clicked on vertical scrollbar
+ // TODO
+ // editField.setVisibleRowNumber(getVerticalValue());
+ }
+
+ // TODO: horizontal scrolling
+ }
+
+ /**
+ * Method that subclasses can override to handle mouse movements.
+ *
+ * @param mouse mouse motion event
+ */
+ @Override
+ public void onMouseMotion(final TMouseEvent mouse) {
+ // Use TWidget's code to pass the event to the children.
+ super.onMouseMotion(mouse);
+
+ if (mouseOnTable(mouse) && mouse.isMouse1()) {
+ // The editor might have changed, update the scollbars.
+ // TODO
+ /*
+ setBottomValue(editField.getMaximumRowNumber());
+ setVerticalValue(editField.getVisibleRowNumber());
+ setRightValue(editField.getMaximumColumnNumber());
+ setHorizontalValue(editField.getEditingColumnNumber());
+ */
+ } else {
+ if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
+ // Clicked/dragged on vertical scrollbar
+ // TODO
+ // editField.setVisibleRowNumber(getVerticalValue());
+ }
+
+ // TODO: horizontal scrolling
+ }
+
+ }
+
+ /**
+ * Handle keystrokes.
+ *
+ * @param keypress keystroke event
+ */
+ @Override
+ public void onKeypress(final TKeypressEvent keypress) {
+ // Use TWidget's code to pass the event to the children.
+ super.onKeypress(keypress);
+
+ // The editor might have changed, update the scollbars.
+ // TODO
+ /*
+ setBottomValue(editField.getMaximumRowNumber());
+ setVerticalValue(editField.getVisibleRowNumber());
+ setRightValue(editField.getMaximumColumnNumber());
+ setHorizontalValue(editField.getEditingColumnNumber());
+ */
+ }
+
+ /**
+ * Handle window/screen resize events.
+ *
+ * @param event resize event
+ */
+ @Override
+ public void onResize(final TResizeEvent event) {
+ if (event.getType() == TResizeEvent.Type.WIDGET) {
+ // Resize the table
+ TResizeEvent tableSize = new TResizeEvent(TResizeEvent.Type.WIDGET,
+ event.getWidth() - 2, event.getHeight() - 2);
+ tableField.onResize(tableSize);
+
+ // Have TScrollableWindow handle the scrollbars
+ super.onResize(event);
+ return;
+ }
+
+ // Pass to children instead
+ for (TWidget widget: getChildren()) {
+ widget.onResize(event);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // TTableWindow -----------------------------------------------------------
+ // ------------------------------------------------------------------------
+
+ /**
+ * Setup other fields after the table is created.
+ */
+ private void setupAfterTable() {
+ hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
+ vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
+ setMinimumWindowWidth(25);
+ setMinimumWindowHeight(10);
+ setTopValue(1);
+ // setBottomValue(editField.getMaximumRowNumber());
+ setLeftValue(1);
+ // setRightValue(editField.getMaximumColumnNumber());
+
+ statusBar = newStatusBar(i18n.getString("statusBar"));
+ statusBar.addShortcutKeypress(kbF1, cmHelp,
+ i18n.getString("statusBarHelp"));
+ /*
+ statusBar.addShortcutKeypress(kbF2, cmSave,
+ i18n.getString("statusBarSave"));
+ statusBar.addShortcutKeypress(kbF3, cmOpen,
+ i18n.getString("statusBarOpen"));
+ */
+ statusBar.addShortcutKeypress(kbF10, cmMenu,
+ i18n.getString("statusBarMenu"));
+ }
+
+ /**
+ * Check if a mouse press/release/motion event coordinate is over the
+ * table.
+ *
+ * @param mouse a mouse-based event
+ * @return whether or not the mouse is on the table
+ */
+ private boolean mouseOnTable(final TMouseEvent mouse) {
+ if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
+ && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
+ && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
+ && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
+ ) {
+ return true;
+ }
+ return false;
+ }
+
+}
--- /dev/null
+statusBar=Editor
+statusBarHelp=Help
+statusBarMenu=Menu
color.setBold(false);
colors.put("teditor", color);
+ // TTable
+ color = new CellAttributes();
+ color.setForeColor(Color.WHITE);
+ color.setBackColor(Color.BLUE);
+ color.setBold(false);
+ colors.put("ttable.inactive", color);
+ color = new CellAttributes();
+ color.setForeColor(Color.BLACK);
+ color.setBackColor(Color.CYAN);
+ color.setBold(false);
+ colors.put("ttable.active", color);
+
}
/**
format(i18n.getString("newConnection"), socket));
DemoApplication app = new DemoApplication(socket.getInputStream(),
socket.getOutputStream());
+ (new Thread(app)).start();
+ Thread.sleep(500);
+ System.out.println(MessageFormat.
+ format(i18n.getString("terminal"),
+ ((jexer.net.TelnetInputStream) socket.getInputStream()).
+ getTerminalType()));
+ System.out.println(MessageFormat.
+ format(i18n.getString("username"),
+ ((jexer.net.TelnetInputStream) socket.getInputStream()).
+ getUsername()));
System.out.println(MessageFormat.
format(i18n.getString("language"),
((jexer.net.TelnetInputStream) socket.getInputStream()).
getLanguage()));
- (new Thread(app)).start();
}
} catch (Exception e) {
e.printStackTrace();
usageString=USAGE: java -cp jexer.jar jexer.demos.Demo2 port
newConnection=New connection: {0}
+username=\ \ \ username: {0}
language=\ \ \ language: {0}
+terminal=\ \ \ terminal: {0}
item = swingMenu.addItem(3001, i18n.getString("smaller"));
}
+ addTableMenu();
addWindowMenu();
addHelpMenu();
}
import jexer.TEditorWindow;
import jexer.TLabel;
import jexer.TProgressBar;
+import jexer.TTableWindow;
import jexer.TTimer;
import jexer.TWidget;
import jexer.TWindow;
private DemoMainWindow(final TApplication parent, final int flags) {
// Construct a demo window. X and Y don't matter because it will be
// centered on screen.
- super(parent, i18n.getString("windowTitle"), 0, 0, 64, 23, flags);
+ super(parent, i18n.getString("windowTitle"), 0, 0, 64, 25, flags);
int row = 1;
);
row += 2;
+ addLabel(i18n.getString("ttableLabel"), 1, row);
+ addButton(i18n.getString("ttableButton1"), 35, row,
+ new TAction() {
+ public void DO() {
+ // TODO
+ }
+ }
+ );
+ addButton(i18n.getString("ttableButton2"), 48, row,
+ new TAction() {
+ public void DO() {
+ new TTableWindow(getApplication(),
+ i18n.getString("tableDemo"));
+ }
+ }
+ );
+ row += 2;
+
addLabel(i18n.getString("treeViewLabel"), 1, row);
addButton(i18n.getString("treeViewButton"), 35, row,
new TAction() {
editorLabel=Editor window
editorButton1=&1 Widget
editorButton2=&2 Window
+ttableLabel=TTable
+ttableButton1=&3 Widget
+ttableButton2=&4 Window
textAreaLabel=Text areas
textAreaButton=&Text
treeViewLabel=Tree views
errorTitle=Error
errorReadingFile=Error reading file: {0}
errorOpeningFile=Error opening file dialog: {0}
+
+tableDemo=TTableWindow Demo
public static final int MID_HELP_ACTIVE_FILE = 55;
public static final int MID_ABOUT = 56;
+ // Table menu
+ public static final int MID_TABLE_BORDER_NONE = 60;
+ public static final int MID_TABLE_BORDER_ALL = 61;
+ public static final int MID_TABLE_BORDER_RIGHT = 62;
+ public static final int MID_TABLE_BORDER_LEFT = 63;
+ public static final int MID_TABLE_BORDER_TOP = 64;
+ public static final int MID_TABLE_BORDER_BOTTOM = 65;
+ public static final int MID_TABLE_BORDER_DOUBLE_BOTTOM = 66;
+ public static final int MID_TABLE_BORDER_THICK_BOTTOM = 67;
+ public static final int MID_TABLE_DELETE_LEFT = 68;
+ public static final int MID_TABLE_DELETE_UP = 69;
+ public static final int MID_TABLE_DELETE_ROW = 70;
+ public static final int MID_TABLE_DELETE_COLUMN = 71;
+ public static final int MID_TABLE_INSERT_LEFT = 72;
+ public static final int MID_TABLE_INSERT_RIGHT = 73;
+ public static final int MID_TABLE_INSERT_ABOVE = 74;
+ public static final int MID_TABLE_INSERT_BELOW = 75;
+ public static final int MID_TABLE_COLUMN_NARROW = 76;
+ public static final int MID_TABLE_COLUMN_WIDEN = 77;
+ public static final int MID_TABLE_FILE_SAVE_CSV = 78;
+ public static final int MID_TABLE_FILE_SAVE_TEXT = 79;
+
// ------------------------------------------------------------------------
// Variables --------------------------------------------------------------
// ------------------------------------------------------------------------
label = i18n.getString("menuHelpAbout");
break;
+ case MID_TABLE_BORDER_NONE:
+ label = i18n.getString("menuTableBorderNone");
+ break;
+ case MID_TABLE_BORDER_ALL:
+ label = i18n.getString("menuTableBorderAll");
+ break;
+ case MID_TABLE_BORDER_RIGHT:
+ label = i18n.getString("menuTableBorderRight");
+ break;
+ case MID_TABLE_BORDER_LEFT:
+ label = i18n.getString("menuTableBorderLeft");
+ break;
+ case MID_TABLE_BORDER_TOP:
+ label = i18n.getString("menuTableBorderTop");
+ break;
+ case MID_TABLE_BORDER_BOTTOM:
+ label = i18n.getString("menuTableBorderBottom");
+ break;
+ case MID_TABLE_BORDER_DOUBLE_BOTTOM:
+ label = i18n.getString("menuTableBorderDoubleBottom");
+ break;
+ case MID_TABLE_BORDER_THICK_BOTTOM:
+ label = i18n.getString("menuTableBorderThickBottom");
+ break;
+ case MID_TABLE_DELETE_LEFT:
+ label = i18n.getString("menuTableDeleteLeft");
+ break;
+ case MID_TABLE_DELETE_UP:
+ label = i18n.getString("menuTableDeleteUp");
+ break;
+ case MID_TABLE_DELETE_ROW:
+ label = i18n.getString("menuTableDeleteRow");
+ break;
+ case MID_TABLE_DELETE_COLUMN:
+ label = i18n.getString("menuTableDeleteColumn");
+ break;
+ case MID_TABLE_INSERT_LEFT:
+ label = i18n.getString("menuTableInsertLeft");
+ break;
+ case MID_TABLE_INSERT_RIGHT:
+ label = i18n.getString("menuTableInsertRight");
+ break;
+ case MID_TABLE_INSERT_ABOVE:
+ label = i18n.getString("menuTableInsertAbove");
+ break;
+ case MID_TABLE_INSERT_BELOW:
+ label = i18n.getString("menuTableInsertBelow");
+ break;
+ case MID_TABLE_COLUMN_NARROW:
+ label = i18n.getString("menuTableColumnNarrow");
+ key = kbShiftLeft;
+ break;
+ case MID_TABLE_COLUMN_WIDEN:
+ label = i18n.getString("menuTableColumnWiden");
+ key = kbShiftRight;
+ break;
+ case MID_TABLE_FILE_SAVE_CSV:
+ label = i18n.getString("menuTableFileSaveCsv");
+ break;
+ case MID_TABLE_FILE_SAVE_TEXT:
+ label = i18n.getString("menuTableFileSaveText");
+ break;
+
default:
throw new IllegalArgumentException("Invalid menu ID: " + id);
}
menuHelpActive=Active &file...
menuHelpAbout=&About...
+menuTableBorderNone=&None
+menuTableBorderAll=&All
+menuTableBorderRight=&Right
+menuTableBorderLeft=&Left
+menuTableBorderTop=&Top
+menuTableBorderBottom=&Bottom
+menuTableBorderDoubleBottom=Bottom (&double)
+menuTableBorderThickBottom=Bottom (t&hick)
+menuTableDeleteLeft=Cell (Shift &Left)
+menuTableDeleteUp=Cell (Shift &Up)
+menuTableDeleteRow=Entire &Row
+menuTableDeleteColumn=Entire &Column
+menuTableInsertLeft=Column &Left
+menuTableInsertRight=Column &Right
+menuTableInsertAbove=Row &Above
+menuTableInsertBelow=Row &Below
+menuTableColumnNarrow=&Narrow
+menuTableColumnWiden=&Widen
+menuTableFileSaveCsv=Save As &CSV...
+menuTableFileSaveText=Save As &Text...
+
menuRepaintDesktop=&Repaint desktop
menuViewImage=&Open image...
menuChangeFont=Change &font...
return menu.addDefaultItem(id);
}
+ /**
+ * Convenience function to add one of the default menu items.
+ *
+ * @param id menu item ID. Must be between 0 (inclusive) and 1023
+ * (inclusive).
+ * @param enabled default state for enabled
+ * @return the new menu item
+ */
+ public TMenuItem addDefaultItem(final int id, final boolean enabled) {
+ return menu.addDefaultItem(id, enabled);
+ }
+
/**
* Convenience function to add a menu separator.
*/
this.language = language;
}
+ /**
+ * Get the terminal type as reported by the telnet Terminal Type option.
+ *
+ * @return the terminal type
+ */
+ public String getTerminalType() {
+ return master.terminalType;
+ }
+
/**
* Text window width getter.
*
// If we got something, return it.
if (rc > 0) {
+ readBufferEnd += rc;
readBufferStart++;
return readBuffer[readBufferStart - 1];
}