2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.util
.ArrayList
;
32 import java
.util
.List
;
33 import java
.util
.ResourceBundle
;
35 import jexer
.bits
.StringUtils
;
36 import jexer
.event
.TKeypressEvent
;
37 import static jexer
.TKeypress
.*;
40 * TMessageBox is a system-modal dialog with buttons for OK, Cancel, Yes, or
45 * box = messageBox(title, caption,
46 * TMessageBox.Type.OK | TMessageBox.Type.CANCEL);
48 * if (box.getResult() == TMessageBox.OK) {
49 * ... the user pressed OK, do stuff ...
55 public class TMessageBox
extends TWindow
{
60 private static final ResourceBundle i18n
= ResourceBundle
.getBundle(TMessageBox
.class.getName());
62 // ------------------------------------------------------------------------
63 // Constants --------------------------------------------------------------
64 // ------------------------------------------------------------------------
67 * Message boxes have these supported types.
76 * Show both OK and Cancel buttons.
81 * Show both Yes and No buttons.
86 * Show Yes, No, and Cancel buttons.
92 * Message boxes have these possible results.
101 * User clicked "Cancel".
106 * User clicked "Yes".
116 // ------------------------------------------------------------------------
117 // Variables --------------------------------------------------------------
118 // ------------------------------------------------------------------------
121 * The type of this message box.
128 private List
<TButton
> buttons
;
131 * Which button was clicked: OK, CANCEL, YES, or NO.
133 private Result result
= Result
.OK
;
135 // ------------------------------------------------------------------------
136 // Constructors -----------------------------------------------------------
137 // ------------------------------------------------------------------------
140 * Public constructor. The message box will be centered on screen.
142 * @param application TApplication that manages this window
143 * @param title window title, will be centered along the top border
144 * @param caption message to display. Use embedded newlines to get a
147 public TMessageBox(final TApplication application
, final String title
,
148 final String caption
) {
150 this(application
, title
, caption
, Type
.OK
, true);
154 * Public constructor. The message box will be centered on screen.
156 * @param application TApplication that manages this window
157 * @param title window title, will be centered along the top border
158 * @param caption message to display. Use embedded newlines to get a
160 * @param type one of the Type constants. Default is Type.OK.
162 public TMessageBox(final TApplication application
, final String title
,
163 final String caption
, final Type type
) {
165 this(application
, title
, caption
, type
, true);
169 * Public constructor. The message box will be centered on screen.
171 * @param application TApplication that manages this window
172 * @param title window title, will be centered along the top border
173 * @param caption message to display. Use embedded newlines to get a
175 * @param type one of the Type constants. Default is Type.OK.
176 * @param yield if true, yield this Thread. Subclasses need to set this
177 * to false and yield at their end of their constructor intead.
179 protected TMessageBox(final TApplication application
, final String title
,
180 final String caption
, final Type type
, final boolean yield
) {
182 // Start as 100x100 at (1, 1). These will be changed later.
183 super(application
, title
, 1, 1, 100, 100, CENTERED
| MODAL
);
185 // Hang onto type so that we can provide more convenience in
189 // Determine width and height
190 String
[] lines
= caption
.split("\n");
191 int width
= StringUtils
.width(title
) + 12;
192 setHeight(6 + lines
.length
);
193 for (String line
: lines
) {
194 if (StringUtils
.width(line
) + 4 > width
) {
195 width
= StringUtils
.width(line
) + 4;
199 if (getWidth() > getScreen().getWidth()) {
200 setWidth(getScreen().getWidth());
202 // Re-center window to get an appropriate (x, y)
205 // Now add my elements
207 for (String line
: lines
) {
208 addLabel(line
, 1, lineI
, "twindow.background.modal");
214 buttons
= new ArrayList
<TButton
>();
218 // Setup button actions
223 if (getWidth() < 15) {
226 buttonX
= (getWidth() - 11) / 2;
227 buttons
.add(addButton(i18n
.getString("okButton"), buttonX
, lineI
,
231 getApplication().closeWindow(TMessageBox
.this);
239 result
= Result
.CANCEL
;
240 if (getWidth() < 26) {
243 buttonX
= (getWidth() - 22) / 2;
244 buttons
.add(addButton(i18n
.getString("okButton"), buttonX
, lineI
,
248 getApplication().closeWindow(TMessageBox
.this);
254 buttons
.add(addButton(i18n
.getString("cancelButton"), buttonX
, lineI
,
257 result
= Result
.CANCEL
;
258 getApplication().closeWindow(TMessageBox
.this);
267 if (getWidth() < 20) {
270 buttonX
= (getWidth() - 16) / 2;
271 buttons
.add(addButton(i18n
.getString("yesButton"), buttonX
, lineI
,
275 getApplication().closeWindow(TMessageBox
.this);
281 buttons
.add(addButton(i18n
.getString("noButton"), buttonX
, lineI
,
285 getApplication().closeWindow(TMessageBox
.this);
293 result
= Result
.CANCEL
;
294 if (getWidth() < 31) {
297 buttonX
= (getWidth() - 27) / 2;
298 buttons
.add(addButton(i18n
.getString("yesButton"), buttonX
, lineI
,
302 getApplication().closeWindow(TMessageBox
.this);
308 buttons
.add(addButton(i18n
.getString("noButton"), buttonX
, lineI
,
312 getApplication().closeWindow(TMessageBox
.this);
318 buttons
.add(addButton(i18n
.getString("cancelButton"), buttonX
,
322 result
= Result
.CANCEL
;
323 getApplication().closeWindow(TMessageBox
.this);
331 throw new IllegalArgumentException("Invalid message box type: " +
336 // Set the secondaryThread to run me
337 getApplication().enableSecondaryEventReceiver(this);
339 // Yield to the secondary thread. When I come back from the
340 // constructor response will already be set.
341 getApplication().yield();
345 // ------------------------------------------------------------------------
346 // TWindow ----------------------------------------------------------------
347 // ------------------------------------------------------------------------
352 * @param keypress keystroke event
355 public void onKeypress(final TKeypressEvent keypress
) {
357 if (this instanceof TInputBox
) {
358 super.onKeypress(keypress
);
362 // Some convenience for message boxes: Alt won't be needed for the
367 if (keypress
.equals(kbO
)) {
368 buttons
.get(0).dispatch();
374 if (keypress
.equals(kbO
)) {
375 buttons
.get(0).dispatch();
377 } else if (keypress
.equals(kbC
)) {
378 buttons
.get(1).dispatch();
384 if (keypress
.equals(kbY
)) {
385 buttons
.get(0).dispatch();
387 } else if (keypress
.equals(kbN
)) {
388 buttons
.get(1).dispatch();
394 if (keypress
.equals(kbY
)) {
395 buttons
.get(0).dispatch();
397 } else if (keypress
.equals(kbN
)) {
398 buttons
.get(1).dispatch();
400 } else if (keypress
.equals(kbC
)) {
401 buttons
.get(2).dispatch();
407 throw new IllegalArgumentException("Invalid message box type: " +
411 super.onKeypress(keypress
);
414 // ------------------------------------------------------------------------
415 // TMessageBox ------------------------------------------------------------
416 // ------------------------------------------------------------------------
421 * @return the result: OK, CANCEL, YES, or NO.
423 public final Result
getResult() {
428 * See if the user clicked YES.
430 * @return true if the user clicked YES
432 public final boolean isYes() {
433 return (result
== Result
.YES
);
437 * See if the user clicked NO.
439 * @return true if the user clicked NO
441 public final boolean isNo() {
442 return (result
== Result
.NO
);
446 * See if the user clicked OK.
448 * @return true if the user clicked OK
450 public final boolean isOk() {
451 return (result
== Result
.OK
);
455 * See if the user clicked CANCEL.
457 * @return true if the user clicked CANCEL
459 public final boolean isCancel() {
460 return (result
== Result
.CANCEL
);