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