stubs for drawing borders
[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
78 tableField = new TTableWidget(this, 0, 0, getWidth() - 2, getHeight() - 2);
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);
77961919
KL
93 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
94 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
95 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
96 getApplication().enableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
1dac6b8d
KL
97 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
98 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
99 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
100 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
101 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
102 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
103 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
104 getApplication().enableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
105 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
106 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_UP);
107 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
108 getApplication().enableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
109 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
110 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
111 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
112 getApplication().enableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
113 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
114 getApplication().enableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
115 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
116 getApplication().enableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
117 }
118
119 /**
120 * Called by application.switchWindow() when another window gets the
121 * focus.
122 */
123 public void onUnfocus() {
124 // Disable the table menu items.
125 getApplication().disableMenuItem(TMenu.MID_CUT);
77961919
KL
126 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_ROW_LABELS);
127 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_COLUMN_LABELS);
128 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_ROW);
129 getApplication().disableMenuItem(TMenu.MID_TABLE_VIEW_HIGHLIGHT_COLUMN);
1dac6b8d
KL
130 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_NONE);
131 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_ALL);
132 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_RIGHT);
133 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_LEFT);
134 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_TOP);
135 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_BOTTOM);
136 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_DOUBLE_BOTTOM);
137 getApplication().disableMenuItem(TMenu.MID_TABLE_BORDER_THICK_BOTTOM);
138 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_LEFT);
139 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_UP);
140 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_ROW);
141 getApplication().disableMenuItem(TMenu.MID_TABLE_DELETE_COLUMN);
142 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_LEFT);
143 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_RIGHT);
144 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_ABOVE);
145 getApplication().disableMenuItem(TMenu.MID_TABLE_INSERT_BELOW);
146 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_NARROW);
147 getApplication().disableMenuItem(TMenu.MID_TABLE_COLUMN_WIDEN);
148 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_CSV);
149 getApplication().disableMenuItem(TMenu.MID_TABLE_FILE_SAVE_TEXT);
150 }
151
152 // ------------------------------------------------------------------------
153 // TWindow ----------------------------------------------------------------
154 // ------------------------------------------------------------------------
155
1dac6b8d
KL
156 /**
157 * Handle mouse press events.
158 *
159 * @param mouse mouse button press event
160 */
161 @Override
162 public void onMouseDown(final TMouseEvent mouse) {
163 // Use TWidget's code to pass the event to the children.
164 super.onMouseDown(mouse);
165
166 if (mouseOnTable(mouse)) {
167 // The table might have changed, update the scollbars.
759cb83e
KL
168 setBottomValue(tableField.getRowCount() - 1);
169 setVerticalValue(tableField.getSelectedRowNumber());
170 setRightValue(tableField.getColumnCount() - 1);
171 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
172 }
173 }
174
175 /**
176 * Handle mouse release events.
177 *
178 * @param mouse mouse button release event
179 */
180 @Override
181 public void onMouseUp(final TMouseEvent mouse) {
182 // Use TWidget's code to pass the event to the children.
183 super.onMouseUp(mouse);
184
185 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
759cb83e
KL
186 // Clicked/dragged on vertical scrollbar.
187 tableField.setSelectedRowNumber(getVerticalValue());
188 }
189 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
190 // Clicked/dragged on horizontal scrollbar.
191 tableField.setSelectedColumnNumber(getHorizontalValue());
1dac6b8d 192 }
1dac6b8d
KL
193 }
194
195 /**
196 * Method that subclasses can override to handle mouse movements.
197 *
198 * @param mouse mouse motion event
199 */
200 @Override
201 public void onMouseMotion(final TMouseEvent mouse) {
202 // Use TWidget's code to pass the event to the children.
203 super.onMouseMotion(mouse);
204
205 if (mouseOnTable(mouse) && mouse.isMouse1()) {
759cb83e
KL
206 // The table might have changed, update the scollbars.
207 setBottomValue(tableField.getRowCount() - 1);
208 setVerticalValue(tableField.getSelectedRowNumber());
209 setRightValue(tableField.getColumnCount() - 1);
210 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
211 } else {
212 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
759cb83e
KL
213 // Clicked/dragged on vertical scrollbar.
214 tableField.setSelectedRowNumber(getVerticalValue());
215 }
216 if (mouse.isMouse1() && mouseOnHorizontalScroller(mouse)) {
217 // Clicked/dragged on horizontal scrollbar.
218 tableField.setSelectedColumnNumber(getHorizontalValue());
1dac6b8d 219 }
1dac6b8d
KL
220 }
221
222 }
223
224 /**
225 * Handle keystrokes.
226 *
227 * @param keypress keystroke event
228 */
229 @Override
230 public void onKeypress(final TKeypressEvent keypress) {
231 // Use TWidget's code to pass the event to the children.
232 super.onKeypress(keypress);
233
759cb83e
KL
234 // The table might have changed, update the scollbars.
235 setBottomValue(tableField.getRowCount() - 1);
236 setVerticalValue(tableField.getSelectedRowNumber());
237 setRightValue(tableField.getColumnCount() - 1);
238 setHorizontalValue(tableField.getSelectedColumnNumber());
1dac6b8d
KL
239 }
240
241 /**
242 * Handle window/screen resize events.
243 *
244 * @param event resize event
245 */
246 @Override
247 public void onResize(final TResizeEvent event) {
248 if (event.getType() == TResizeEvent.Type.WIDGET) {
249 // Resize the table
250 TResizeEvent tableSize = new TResizeEvent(TResizeEvent.Type.WIDGET,
251 event.getWidth() - 2, event.getHeight() - 2);
252 tableField.onResize(tableSize);
253
254 // Have TScrollableWindow handle the scrollbars
255 super.onResize(event);
256 return;
257 }
258
259 // Pass to children instead
260 for (TWidget widget: getChildren()) {
261 widget.onResize(event);
262 }
263 }
264
759cb83e
KL
265 /**
266 * Method that subclasses can override to handle posted command events.
267 *
268 * @param command command event
269 */
270 @Override
271 public void onCommand(final TCommandEvent command) {
272 if (command.equals(cmOpen)) {
273 try {
274 String filename = fileOpenBox(".");
275 if (filename != null) {
276 try {
277 // TODO
278 if (false) {
279 tableField.saveToFilename(filename);
280 }
281 } catch (IOException e) {
282 messageBox(i18n.getString("errorDialogTitle"),
283 MessageFormat.format(i18n.
284 getString("errorReadingFile"), e.getMessage()));
285 }
286 }
287 } catch (IOException e) {
288 messageBox(i18n.getString("errorDialogTitle"),
289 MessageFormat.format(i18n.
290 getString("errorOpeningFileDialog"), e.getMessage()));
291 }
292 return;
293 }
294
295 if (command.equals(cmSave)) {
296 try {
297 String filename = fileSaveBox(".");
298 if (filename != null) {
299 tableField.saveToFilename(filename);
300 }
301 } catch (IOException e) {
302 messageBox(i18n.getString("errorDialogTitle"),
303 MessageFormat.format(i18n.
304 getString("errorSavingFile"), e.getMessage()));
305 }
306 return;
307 }
308
309 // Didn't handle it, let children get it instead
310 super.onCommand(command);
311 }
312
1dac6b8d
KL
313 // ------------------------------------------------------------------------
314 // TTableWindow -----------------------------------------------------------
315 // ------------------------------------------------------------------------
316
317 /**
318 * Setup other fields after the table is created.
319 */
320 private void setupAfterTable() {
321 hScroller = new THScroller(this, 17, getHeight() - 2, getWidth() - 20);
322 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
323 setMinimumWindowWidth(25);
324 setMinimumWindowHeight(10);
759cb83e
KL
325 setTopValue(tableField.getSelectedRowNumber());
326 setBottomValue(tableField.getRowCount() - 1);
327 setLeftValue(tableField.getSelectedColumnNumber());
328 setRightValue(tableField.getColumnCount() - 1);
1dac6b8d
KL
329
330 statusBar = newStatusBar(i18n.getString("statusBar"));
331 statusBar.addShortcutKeypress(kbF1, cmHelp,
332 i18n.getString("statusBarHelp"));
759cb83e 333
1dac6b8d
KL
334 statusBar.addShortcutKeypress(kbF2, cmSave,
335 i18n.getString("statusBarSave"));
336 statusBar.addShortcutKeypress(kbF3, cmOpen,
337 i18n.getString("statusBarOpen"));
1dac6b8d
KL
338 statusBar.addShortcutKeypress(kbF10, cmMenu,
339 i18n.getString("statusBarMenu"));
340 }
341
342 /**
343 * Check if a mouse press/release/motion event coordinate is over the
344 * table.
345 *
346 * @param mouse a mouse-based event
347 * @return whether or not the mouse is on the table
348 */
349 private boolean mouseOnTable(final TMouseEvent mouse) {
350 if ((mouse.getAbsoluteX() >= getAbsoluteX() + 1)
351 && (mouse.getAbsoluteX() < getAbsoluteX() + getWidth() - 1)
352 && (mouse.getAbsoluteY() >= getAbsoluteY() + 1)
353 && (mouse.getAbsoluteY() < getAbsoluteY() + getHeight() - 1)
354 ) {
355 return true;
356 }
357 return false;
358 }
359
360}