retrofit
[fanfix.git] / src / jexer / TTerminalWindow.java
CommitLineData
daa4106c 1/*
34a42e78
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
34a42e78 5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
34a42e78 7 *
e16dda65
KL
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:
34a42e78 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
34a42e78 17 *
e16dda65
KL
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.
34a42e78
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
339652cc 31import java.util.ResourceBundle;
34a42e78 32
3c5921e6 33import jexer.menu.TMenu;
34a42e78 34import jexer.event.TKeypressEvent;
b2d49e0f 35import jexer.event.TMenuEvent;
34a42e78
KL
36import jexer.event.TMouseEvent;
37import jexer.event.TResizeEvent;
34a42e78
KL
38import static jexer.TKeypress.*;
39
40/**
41 * TTerminalWindow exposes a ECMA-48 / ANSI X3.64 style terminal in a window.
42 */
4d2c61b4 43public class TTerminalWindow extends TScrollableWindow {
34a42e78 44
339652cc
KL
45 /**
46 * Translated strings.
47 */
48 private static final ResourceBundle i18n = ResourceBundle.getBundle(TTerminalWindow.class.getName());
49
615a0d99
KL
50 // ------------------------------------------------------------------------
51 // Variables --------------------------------------------------------------
52 // ------------------------------------------------------------------------
53
34a42e78 54 /**
4d2c61b4 55 * The terminal.
34a42e78 56 */
4d2c61b4 57 private TTerminalWidget terminal;
1d99a38f 58
a69ed767
KL
59 /**
60 * If true, close the window when the shell exits.
61 */
62 private boolean closeOnExit = false;
63
615a0d99
KL
64 // ------------------------------------------------------------------------
65 // Constructors -----------------------------------------------------------
66 // ------------------------------------------------------------------------
34a42e78 67
b2d49e0f
KL
68 /**
69 * Public constructor spawns a custom command line.
70 *
71 * @param application TApplication that manages this window
72 * @param x column relative to parent
73 * @param y row relative to parent
74 * @param commandLine the command line to execute
75 */
76 public TTerminalWindow(final TApplication application, final int x,
77 final int y, final String commandLine) {
78
00691e80 79 this(application, x, y, RESIZABLE, commandLine.split("\\s+"),
a69ed767
KL
80 System.getProperty("jexer.TTerminal.closeOnExit",
81 "false").equals("true"));
82 }
83
84 /**
85 * Public constructor spawns a custom command line.
86 *
87 * @param application TApplication that manages this window
88 * @param x column relative to parent
89 * @param y row relative to parent
90 * @param commandLine the command line to execute
91 * @param closeOnExit if true, close the window when the command exits
92 */
93 public TTerminalWindow(final TApplication application, final int x,
94 final int y, final String commandLine, final boolean closeOnExit) {
95
00691e80 96 this(application, x, y, RESIZABLE, commandLine.split("\\s+"),
a69ed767 97 closeOnExit);
b2d49e0f
KL
98 }
99
6f8ff91a
KL
100 /**
101 * Public constructor spawns a custom command line.
102 *
103 * @param application TApplication that manages this window
104 * @param x column relative to parent
105 * @param y row relative to parent
106 * @param flags mask of CENTERED, MODAL, or RESIZABLE
a0d734e6 107 * @param command the command line to execute
6f8ff91a
KL
108 */
109 public TTerminalWindow(final TApplication application, final int x,
a0d734e6 110 final int y, final int flags, final String [] command) {
6f8ff91a 111
a69ed767
KL
112 this(application, x, y, flags, command,
113 System.getProperty("jexer.TTerminal.closeOnExit",
114 "false").equals("true"));
115 }
116
117 /**
118 * Public constructor spawns a custom command line.
119 *
120 * @param application TApplication that manages this window
121 * @param x column relative to parent
122 * @param y row relative to parent
123 * @param flags mask of CENTERED, MODAL, or RESIZABLE
124 * @param command the command line to execute
125 * @param closeOnExit if true, close the window when the command exits
126 */
127 public TTerminalWindow(final TApplication application, final int x,
128 final int y, final int flags, final String [] command,
129 final boolean closeOnExit) {
130
6f8ff91a
KL
131 super(application, i18n.getString("windowTitle"), x, y,
132 80 + 2, 24 + 2, flags);
133
955c55b7
KL
134 // Require at least one line for the display.
135 setMinimumWindowHeight(3);
136
a69ed767 137 this.closeOnExit = closeOnExit;
4d2c61b4
KL
138 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
139
140 // Claim the keystrokes the emulator will need.
141 addShortcutKeys();
a69ed767 142
4d2c61b4
KL
143 // Add shortcut text
144 newStatusBar(i18n.getString("statusBarRunning"));
6f8ff91a 145
4d2c61b4 146 // Spin it up
5ca5f8e5 147 terminal = new TTerminalWidget(this, 0, 0, command, new TAction() {
2bc32111
KL
148 public void DO() {
149 onShellExit();
150 }
151 });
6f8ff91a
KL
152 }
153
154 /**
155 * Public constructor spawns a shell.
156 *
157 * @param application TApplication that manages this window
158 * @param x column relative to parent
159 * @param y row relative to parent
160 * @param flags mask of CENTERED, MODAL, or RESIZABLE
161 */
162 public TTerminalWindow(final TApplication application, final int x,
163 final int y, final int flags) {
164
a69ed767
KL
165 this(application, x, y, flags,
166 System.getProperty("jexer.TTerminal.closeOnExit",
167 "false").equals("true"));
168
169 }
170
171 /**
172 * Public constructor spawns a shell.
173 *
174 * @param application TApplication that manages this window
175 * @param x column relative to parent
176 * @param y row relative to parent
177 * @param flags mask of CENTERED, MODAL, or RESIZABLE
178 * @param closeOnExit if true, close the window when the shell exits
179 */
180 public TTerminalWindow(final TApplication application, final int x,
181 final int y, final int flags, final boolean closeOnExit) {
182
6f8ff91a
KL
183 super(application, i18n.getString("windowTitle"), x, y,
184 80 + 2, 24 + 2, flags);
185
955c55b7
KL
186 // Require at least one line for the display.
187 setMinimumWindowHeight(3);
188
a69ed767 189 this.closeOnExit = closeOnExit;
4d2c61b4 190 vScroller = new TVScroller(this, getWidth() - 2, 0, getHeight() - 2);
a69ed767 191
4d2c61b4
KL
192 // Claim the keystrokes the emulator will need.
193 addShortcutKeys();
6f8ff91a 194
4d2c61b4
KL
195 // Add shortcut text
196 newStatusBar(i18n.getString("statusBarRunning"));
6f8ff91a 197
4d2c61b4 198 // Spin it up
2bc32111
KL
199 terminal = new TTerminalWidget(this, 0, 0, new TAction() {
200 public void DO() {
201 onShellExit();
202 }
203 });
6f8ff91a
KL
204 }
205
615a0d99
KL
206 // ------------------------------------------------------------------------
207 // TScrollableWindow ------------------------------------------------------
208 // ------------------------------------------------------------------------
55d2b2c2 209
34a42e78
KL
210 /**
211 * Draw the display buffer.
212 */
213 @Override
214 public void draw() {
1104f8d7
KL
215 if (terminal != null) {
216 setTitle(terminal.getTitle());
217 }
4d2c61b4 218 reflowData();
ab215e38 219 super.draw();
107bba16
KL
220 }
221
be72cb5c 222 /**
615a0d99 223 * Handle window/screen resize events.
aa77d682 224 *
615a0d99 225 * @param resize resize event
aa77d682 226 */
615a0d99
KL
227 @Override
228 public void onResize(final TResizeEvent resize) {
4d2c61b4 229 if (resize.getType() == TResizeEvent.Type.WIDGET) {
1104f8d7
KL
230 if (terminal != null) {
231 terminal.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
232 getWidth() - 2, getHeight() - 2));
233 }
615a0d99 234
4d2c61b4
KL
235 // Resize the scroll bars
236 reflowData();
237 placeScrollbars();
238 }
239 return;
aa77d682
KL
240 }
241
242 /**
615a0d99 243 * Resize scrollbars for a new width/height.
aa77d682 244 */
615a0d99
KL
245 @Override
246 public void reflowData() {
4d2c61b4 247 // Vertical scrollbar
1104f8d7
KL
248 if (terminal != null) {
249 terminal.reflowData();
250 setTopValue(terminal.getTopValue());
251 setBottomValue(terminal.getBottomValue());
252 setVerticalBigChange(terminal.getVerticalBigChange());
253 setVerticalValue(terminal.getVerticalValue());
254 }
aa77d682
KL
255 }
256
b2d49e0f 257 /**
615a0d99
KL
258 * Handle keystrokes.
259 *
260 * @param keypress keystroke event
34a42e78 261 */
615a0d99
KL
262 @Override
263 public void onKeypress(final TKeypressEvent keypress) {
1104f8d7 264 if ((terminal != null) && (terminal.isReading())) {
4d2c61b4
KL
265 terminal.onKeypress(keypress);
266 } else {
267 super.onKeypress(keypress);
34a42e78 268 }
34a42e78
KL
269 }
270
271 /**
272 * Handle mouse press events.
273 *
274 * @param mouse mouse button press event
275 */
276 @Override
277 public void onMouseDown(final TMouseEvent mouse) {
bd8d51fa
KL
278 if (inWindowMove || inWindowResize) {
279 // TWindow needs to deal with this.
280 super.onMouseDown(mouse);
281 return;
282 }
34a42e78 283
34a42e78
KL
284 super.onMouseDown(mouse);
285 }
286
bd8d51fa
KL
287 /**
288 * Handle mouse release events.
289 *
290 * @param mouse mouse button release event
291 */
292 @Override
293 public void onMouseUp(final TMouseEvent mouse) {
294 if (inWindowMove || inWindowResize) {
295 // TWindow needs to deal with this.
296 super.onMouseUp(mouse);
297 return;
298 }
299
bd8d51fa 300 super.onMouseUp(mouse);
dbf8e80a
KL
301
302 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
303 // Clicked on vertical scrollbar
1104f8d7
KL
304 if (terminal != null) {
305 terminal.setVerticalValue(getVerticalValue());
306 }
dbf8e80a 307 }
bd8d51fa
KL
308 }
309
310 /**
311 * Handle mouse motion events.
312 *
313 * @param mouse mouse motion event
314 */
315 @Override
316 public void onMouseMotion(final TMouseEvent mouse) {
317 if (inWindowMove || inWindowResize) {
318 // TWindow needs to deal with this.
319 super.onMouseMotion(mouse);
320 return;
321 }
322
bd8d51fa 323 super.onMouseMotion(mouse);
dbf8e80a
KL
324
325 if (mouse.isMouse1() && mouseOnVerticalScroller(mouse)) {
326 // Clicked/dragged on vertical scrollbar
1104f8d7
KL
327 if (terminal != null) {
328 terminal.setVerticalValue(getVerticalValue());
329 }
dbf8e80a 330 }
bd8d51fa
KL
331 }
332
615a0d99
KL
333 // ------------------------------------------------------------------------
334 // TTerminalWindow --------------------------------------------------------
335 // ------------------------------------------------------------------------
336
80b1b7b5
KL
337 /**
338 * Returns true if this window does not want the application-wide mouse
339 * cursor drawn over it.
340 *
341 * @return true if this window does not want the application-wide mouse
342 * cursor drawn over it
343 */
344 @Override
345 public boolean hasHiddenMouse() {
1104f8d7
KL
346 if (terminal != null) {
347 return terminal.hasHiddenMouse();
348 }
349 return false;
80b1b7b5
KL
350 }
351
615a0d99
KL
352 /**
353 * Claim the keystrokes the emulator will need.
354 */
355 private void addShortcutKeys() {
356 addShortcutKeypress(kbCtrlA);
357 addShortcutKeypress(kbCtrlB);
358 addShortcutKeypress(kbCtrlC);
359 addShortcutKeypress(kbCtrlD);
360 addShortcutKeypress(kbCtrlE);
361 addShortcutKeypress(kbCtrlF);
362 addShortcutKeypress(kbCtrlG);
363 addShortcutKeypress(kbCtrlH);
364 addShortcutKeypress(kbCtrlU);
365 addShortcutKeypress(kbCtrlJ);
366 addShortcutKeypress(kbCtrlK);
367 addShortcutKeypress(kbCtrlL);
368 addShortcutKeypress(kbCtrlM);
369 addShortcutKeypress(kbCtrlN);
370 addShortcutKeypress(kbCtrlO);
371 addShortcutKeypress(kbCtrlP);
372 addShortcutKeypress(kbCtrlQ);
373 addShortcutKeypress(kbCtrlR);
374 addShortcutKeypress(kbCtrlS);
375 addShortcutKeypress(kbCtrlT);
376 addShortcutKeypress(kbCtrlU);
377 addShortcutKeypress(kbCtrlV);
378 addShortcutKeypress(kbCtrlW);
379 addShortcutKeypress(kbCtrlX);
380 addShortcutKeypress(kbCtrlY);
381 addShortcutKeypress(kbCtrlZ);
382 addShortcutKeypress(kbF1);
383 addShortcutKeypress(kbF2);
384 addShortcutKeypress(kbF3);
385 addShortcutKeypress(kbF4);
386 addShortcutKeypress(kbF5);
387 addShortcutKeypress(kbF6);
388 addShortcutKeypress(kbF7);
389 addShortcutKeypress(kbF8);
390 addShortcutKeypress(kbF9);
391 addShortcutKeypress(kbF10);
392 addShortcutKeypress(kbF11);
393 addShortcutKeypress(kbF12);
394 addShortcutKeypress(kbAltA);
395 addShortcutKeypress(kbAltB);
396 addShortcutKeypress(kbAltC);
397 addShortcutKeypress(kbAltD);
398 addShortcutKeypress(kbAltE);
399 addShortcutKeypress(kbAltF);
400 addShortcutKeypress(kbAltG);
401 addShortcutKeypress(kbAltH);
402 addShortcutKeypress(kbAltU);
403 addShortcutKeypress(kbAltJ);
404 addShortcutKeypress(kbAltK);
405 addShortcutKeypress(kbAltL);
406 addShortcutKeypress(kbAltM);
407 addShortcutKeypress(kbAltN);
408 addShortcutKeypress(kbAltO);
409 addShortcutKeypress(kbAltP);
410 addShortcutKeypress(kbAltQ);
411 addShortcutKeypress(kbAltR);
412 addShortcutKeypress(kbAltS);
413 addShortcutKeypress(kbAltT);
414 addShortcutKeypress(kbAltU);
415 addShortcutKeypress(kbAltV);
416 addShortcutKeypress(kbAltW);
417 addShortcutKeypress(kbAltX);
418 addShortcutKeypress(kbAltY);
419 addShortcutKeypress(kbAltZ);
420 }
421
615a0d99
KL
422 /**
423 * Hook for subclasses to be notified of the shell termination.
424 */
425 public void onShellExit() {
a69ed767
KL
426 if (closeOnExit) {
427 close();
428 }
4d2c61b4 429 clearShortcutKeypresses();
615a0d99
KL
430 getApplication().postEvent(new TMenuEvent(TMenu.MID_REPAINT));
431 }
432
5ca5f8e5
KL
433 /**
434 * Wait for a period of time to get output from the launched process.
435 *
436 * @param millis millis to wait for, or 0 to wait forever
437 * @return true if the launched process has emitted something
438 */
439 public boolean waitForOutput(final int millis) {
440 if (terminal == null) {
441 return false;
442 }
443 return terminal.waitForOutput(millis);
444 }
445
34a42e78 446}