ttable delete up/left
[fanfix.git] / src / jexer / TTableWindow.java
CommitLineData
1dac6b8d
KL
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2019 Kevin Lamonte
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
759cb83e
KL
31import java.io.IOException;
32import java.text.MessageFormat;
1dac6b8d
KL
33import java.util.ResourceBundle;
34
35import jexer.event.TCommandEvent;
36import jexer.event.TKeypressEvent;
37import jexer.event.TMouseEvent;
38import jexer.event.TResizeEvent;
39import jexer.menu.TMenu;
40import static jexer.TCommand.*;
41import static jexer.TKeypress.*;
42
43/**
44 * TTableWindow is used to display and edit regular two-dimensional tables of
45 * cells.
46 */
47public class TTableWindow extends TScrollableWindow {
48
49 /**
50 * Translated strings.
51 */
52 private static final ResourceBundle i18n = ResourceBundle.getBundle(TTableWindow.class.getName());
53
54 // ------------------------------------------------------------------------
55 // Variables --------------------------------------------------------------
56 // ------------------------------------------------------------------------
57
58 /**
59 * The table widget.
60 */
61 private TTableWidget tableField;
62
63 // ------------------------------------------------------------------------
64 // Constructors -----------------------------------------------------------
65 // ------------------------------------------------------------------------
66
67 /**
68 * Public constructor sets window title.
69 *
70 * @param parent the main application
71 * @param title the window title
72 */
73 public TTableWindow(final TApplication parent, final String title) {
74
75 super(parent, title, 0, 0, parent.getScreen().getWidth() / 2,
76 parent.getScreen().getHeight() / 2 - 2, RESIZABLE | CENTERED);
77
382bc294 78 tableField = addTable(0, 0, getWidth() - 2, getHeight() - 2);
1dac6b8d
KL
79 setupAfterTable();
80 }
81
82 // ------------------------------------------------------------------------
83 // Event handlers ---------------------------------------------------------
84 // ------------------------------------------------------------------------
85
86 /**
87 * Called by application.switchWindow() when this window gets the
88 * focus, and also by application.addWindow().
89 */
90 public void onFocus() {
91 // Enable the table menu items.
92 getApplication().enableMenuItem(TMenu.MID_CUT);
2b427404
KL
93 getApplication().enableMenuItem(TMenu.MID_TABLE_RENAME_COLUMN);
94 getApplication().enableMenuItem(TMenu.MID_TABLE_RENAME_ROW);
77961919
KL
95 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
96 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
97 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
98 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
1dac6b8d
KL
99 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
100 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
e9bb3c1e
KL
101 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_CELL_NONE);
102 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_CELL_ALL);
1dac6b8d
KL
103 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
104 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
105 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
106 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
107 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
108 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
109 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
110 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_UP);
111 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
112 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
113 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
114 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
115 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
116 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
117 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
118 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
119 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
120 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
121 }
122
123 /**
124 * Called by application.switchWindow() when another window gets the
125 * focus.
126 */
127 public void onUnfocus() {
128 // Disable the table menu items.
129 getApplication().disableMenuItem(TMenu.MID_CUT);
2b427404
KL
130 getApplication().disableMenuItem(TMenu.MID_TABLE_RENAME_COLUMN);
131 getApplication().disableMenuItem(TMenu.MID_TABLE_RENAME_ROW);
77961919
KL
132 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
133 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
134 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
135 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
1dac6b8d
KL
136 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
137 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
e9bb3c1e
KL
138 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_CELL_NONE);
139 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_CELL_ALL);
1dac6b8d
KL
140 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
141 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
142 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
143 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
144 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
145 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
146 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
147 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_UP);
148 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
149 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
150 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
151 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
152 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
153 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
154 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
155 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
156 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
157 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
158 }
159
160 // ------------------------------------------------------------------------
161 // TWindow ----------------------------------------------------------------
162 // ------------------------------------------------------------------------
163
1dac6b8d
KL
164 /**
165 * Handle mouse press events.
166 *
167 * @param mouse mouse button press event
168 */
169 @Override
170 public void onMouseDown(final TMouseEvent mouse) {
171 // Use TWidget's code to pass the event to the children.
172 super.onMouseDown(mouse);
173
174 if (mouseOnTable(mouse)) {
175 // The table might have changed, update the scollbars.
759cb83e
KL
176 setBottomValue(tableField.getRowCount() - 1);
177 setVerticalValue(tableField.getSelectedRowNumber());
178 setRightValue(tableField.getColumnCount() - 1);
179 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
180 }
181 }
182
183 /**
184 * Handle mouse release events.
185 *
186 * @param mouse mouse button release event
187 */
188 @Override
189 public void onMouseUp(final TMouseEvent mouse) {
190 // Use TWidget's code to pass the event to the children.
191 super.onMouseUp(mouse);
192
193 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
759cb83e
KL
194 // Clicked/dragged on vertical scrollbar.
195 tableField.setSelectedRowNumber(getVerticalValue());
196 }
197 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
198 // Clicked/dragged on horizontal scrollbar.
199 tableField.setSelectedColumnNumber(getHorizontalValue());
1dac6b8d 200 }
1dac6b8d
KL
201 }
202
203 /**
204 * Method that subclasses can override to handle mouse movements.
205 *
206 * @param mouse mouse motion event
207 */
208 @Override
209 public void onMouseMotion(final TMouseEvent mouse) {
210 // Use TWidget's code to pass the event to the children.
211 super.onMouseMotion(mouse);
212
213 if (mouseOnTable(mouse) && mouse.isMouse1()) {
759cb83e
KL
214 // The table might have changed, update the scollbars.
215 setBottomValue(tableField.getRowCount() - 1);
216 setVerticalValue(tableField.getSelectedRowNumber());
217 setRightValue(tableField.getColumnCount() - 1);
218 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
219 } else {
220 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
759cb83e
KL
221 // Clicked/dragged on vertical scrollbar.
222 tableField.setSelectedRowNumber(getVerticalValue());
223 }
224 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
225 // Clicked/dragged on horizontal scrollbar.
226 tableField.setSelectedColumnNumber(getHorizontalValue());
1dac6b8d 227 }
1dac6b8d
KL
228 }
229
230 }
231
232 /**
233 * Handle keystrokes.
234 *
235 * @param keypress keystroke event
236 */
237 @Override
238 public void onKeypress(final TKeypressEvent keypress) {
239 // Use TWidget's code to pass the event to the children.
240 super.onKeypress(keypress);
241
759cb83e
KL
242 // The table might have changed, update the scollbars.
243 setBottomValue(tableField.getRowCount() - 1);
244 setVerticalValue(tableField.getSelectedRowNumber());
245 setRightValue(tableField.getColumnCount() - 1);
246 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
247 }
248
249 /**
250 * Handle window/screen resize events.
251 *
252 * @param event resize event
253 */
254 @Override
255 public void onResize(final TResizeEvent event) {
256 if (event.getType() == TResizeEvent.Type.WIDGET) {
257 // Resize the table
258 TResizeEvent tableSize = new TResizeEvent(TResizeEvent.Type.WIDGET,
259 event.getWidth() - 2, event.getHeight() - 2);
260 tableField.onResize(tableSize);
261
262 // Have TScrollableWindow handle the scrollbars
263 super.onResize(event);
264 return;
265 }
266
267 // Pass to children instead
268 for (TWidget widget: getChildren()) {
269 widget.onResize(event);
270 }
271 }
272
759cb83e
KL
273 /**
274 * Method that subclasses can override to handle posted command events.
275 *
276 * @param command command event
277 */
278 @Override
279 public void onCommand(final TCommandEvent command) {
280 if (command.equals(cmOpen)) {
281 try {
282 String filename = fileOpenBox(".");
283 if (filename != null) {
284 try {
285 // TODO
286 if (false) {
287 tableField.saveToFilename(filename);
288 }
289 } catch (IOException e) {
290 messageBox(i18n.getString("errorDialogTitle"),
291 MessageFormat.format(i18n.
292 getString("errorReadingFile"), e.getMessage()));
293 }
294 }
295 } catch (IOException e) {
296 messageBox(i18n.getString("errorDialogTitle"),
297 MessageFormat.format(i18n.
298 getString("errorOpeningFileDialog"), e.getMessage()));
299 }
300 return;
301 }
302
303 if (command.equals(cmSave)) {
304 try {
305 String filename = fileSaveBox(".");
306 if (filename != null) {
307 tableField.saveToFilename(filename);
308 }
309 } catch (IOException e) {
310 messageBox(i18n.getString("errorDialogTitle"),
311 MessageFormat.format(i18n.
312 getString("errorSavingFile"), e.getMessage()));
313 }
314 return;
315 }
316
317 // Didn't handle it, let children get it instead
318 super.onCommand(command);
319 }
320
1dac6b8d
KL
321 // ------------------------------------------------------------------------
322 // TTableWindow -----------------------------------------------------------
323 // ------------------------------------------------------------------------
324
325 /**
326 * Setup other fields after the table is created.
327 */
328 private void setupAfterTable() {
329 hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
330 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
331 setMinimumWindowWidth(25);
332 setMinimumWindowHeight(10);
759cb83e
KL
333 setTopValue(tableField.getSelectedRowNumber());
334 setBottomValue(tableField.getRowCount() - 1);
335 setLeftValue(tableField.getSelectedColumnNumber());
336 setRightValue(tableField.getColumnCount() - 1);
1dac6b8d
KL
337
338 statusBar = newStatusBar(i18n.getString("statusBar"));
339 statusBar.addShortcutKeypress(kbF1, cmHelp,
340 i18n.getString("statusBarHelp"));
759cb83e 341
1dac6b8d
KL
342 statusBar.addShortcutKeypress(kbF2, cmSave,
343 i18n.getString("statusBarSave"));
344 statusBar.addShortcutKeypress(kbF3, cmOpen,
345 i18n.getString("statusBarOpen"));
1dac6b8d
KL
346 statusBar.addShortcutKeypress(kbF10, cmMenu,
347 i18n.getString("statusBarMenu"));
348 }
349
350 /**
351 * Check if a mouse press/release/motion event coordinate is over the
352 * table.
353 *
354 * @param mouse a mouse-based event
355 * @return whether or not the mouse is on the table
356 */
357 private boolean mouseOnTable(final TMouseEvent mouse) {
358 if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
359 && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
360 && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
361 && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
362 ) {
363 return true;
364 }
365 return false;
366 }
367
368}