typos
[fanfix.git] / src / jexer / TMessageBox.java
... / ...
CommitLineData
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (C) 2017 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
31import java.util.ArrayList;
32import java.util.List;
33import java.util.ResourceBundle;
34
35import jexer.event.TKeypressEvent;
36import static jexer.TKeypress.*;
37
38/**
39 * TMessageBox is a system-modal dialog with buttons for OK, Cancel, Yes, or
40 * No. Call it like:
41 *
42 * <pre>
43 * {@code
44 * box = application.messageBox(title, caption,
45 * TMessageBox.Type.OK | TMessageBox.Type.CANCEL);
46 *
47 * if (box.getResult() == TMessageBox.OK) {
48 * ... the user pressed OK, do stuff ...
49 * }
50 * }
51 * </pre>
52 *
53 */
54public class TMessageBox extends TWindow {
55
56 /**
57 * Translated strings.
58 */
59 private static final ResourceBundle i18n = ResourceBundle.getBundle(TMessageBox.class.getName());
60
61 // ------------------------------------------------------------------------
62 // Constants --------------------------------------------------------------
63 // ------------------------------------------------------------------------
64
65 /**
66 * Message boxes have these supported types.
67 */
68 public enum Type {
69 /**
70 * Show an OK button.
71 */
72 OK,
73
74 /**
75 * Show both OK and Cancel buttons.
76 */
77 OKCANCEL,
78
79 /**
80 * Show both Yes and No buttons.
81 */
82 YESNO,
83
84 /**
85 * Show Yes, No, and Cancel buttons.
86 */
87 YESNOCANCEL
88 };
89
90 /**
91 * Message boxes have these possible results.
92 */
93 public enum Result {
94 /**
95 * User clicked "OK".
96 */
97 OK,
98
99 /**
100 * User clicked "Cancel".
101 */
102 CANCEL,
103
104 /**
105 * User clicked "Yes".
106 */
107 YES,
108
109 /**
110 * User clicked "No".
111 */
112 NO
113 };
114
115 // ------------------------------------------------------------------------
116 // Variables --------------------------------------------------------------
117 // ------------------------------------------------------------------------
118
119 /**
120 * The type of this message box.
121 */
122 private Type type;
123
124 /**
125 * My buttons.
126 */
127 private List<TButton> buttons;
128
129 /**
130 * Which button was clicked: OK, CANCEL, YES, or NO.
131 */
132 private Result result = Result.OK;
133
134 // ------------------------------------------------------------------------
135 // Constructors -----------------------------------------------------------
136 // ------------------------------------------------------------------------
137
138 /**
139 * Public constructor. The message box will be centered on screen.
140 *
141 * @param application TApplication that manages this window
142 * @param title window title, will be centered along the top border
143 * @param caption message to display. Use embedded newlines to get a
144 * multi-line box.
145 */
146 public TMessageBox(final TApplication application, final String title,
147 final String caption) {
148
149 this(application, title, caption, Type.OK, true);
150 }
151
152 /**
153 * Public constructor. The message box will be centered on screen.
154 *
155 * @param application TApplication that manages this window
156 * @param title window title, will be centered along the top border
157 * @param caption message to display. Use embedded newlines to get a
158 * multi-line box.
159 * @param type one of the Type constants. Default is Type.OK.
160 */
161 public TMessageBox(final TApplication application, final String title,
162 final String caption, final Type type) {
163
164 this(application, title, caption, type, true);
165 }
166
167 /**
168 * Public constructor. The message box will be centered on screen.
169 *
170 * @param application TApplication that manages this window
171 * @param title window title, will be centered along the top border
172 * @param caption message to display. Use embedded newlines to get a
173 * multi-line box.
174 * @param type one of the Type constants. Default is Type.OK.
175 * @param yield if true, yield this Thread. Subclasses need to set this
176 * to false and yield at their end of their constructor intead.
177 */
178 protected TMessageBox(final TApplication application, final String title,
179 final String caption, final Type type, final boolean yield) {
180
181 // Start as 50x50 at (1, 1). These will be changed later.
182 super(application, title, 1, 1, 100, 100, CENTERED | MODAL);
183
184 // Hang onto type so that we can provide more convenience in
185 // onKeypress().
186 this.type = type;
187
188 // Determine width and height
189 String [] lines = caption.split("\n");
190 int width = title.length() + 12;
191 setHeight(6 + lines.length);
192 for (String line: lines) {
193 if (line.length() + 4 > width) {
194 width = line.length() + 4;
195 }
196 }
197 setWidth(width);
198 if (getWidth() > getScreen().getWidth()) {
199 setWidth(getScreen().getWidth());
200 }
201 // Re-center window to get an appropriate (x, y)
202 center();
203
204 // Now add my elements
205 int lineI = 1;
206 for (String line: lines) {
207 addLabel(line, 1, lineI, "twindow.background.modal");
208 lineI++;
209 }
210
211 // The button line
212 lineI++;
213 buttons = new ArrayList<TButton>();
214
215 int buttonX = 0;
216
217 // Setup button actions
218 switch (type) {
219
220 case OK:
221 result = Result.OK;
222 if (getWidth() < 15) {
223 setWidth(15);
224 }
225 buttonX = (getWidth() - 11) / 2;
226 buttons.add(addButton(i18n.getString("okButton"), buttonX, lineI,
227 new TAction() {
228 public void DO() {
229 result = Result.OK;
230 getApplication().closeWindow(TMessageBox.this);
231 }
232 }
233 )
234 );
235 break;
236
237 case OKCANCEL:
238 result = Result.CANCEL;
239 if (getWidth() < 26) {
240 setWidth(26);
241 }
242 buttonX = (getWidth() - 22) / 2;
243 buttons.add(addButton(i18n.getString("okButton"), buttonX, lineI,
244 new TAction() {
245 public void DO() {
246 result = Result.OK;
247 getApplication().closeWindow(TMessageBox.this);
248 }
249 }
250 )
251 );
252 buttonX += 8 + 4;
253 buttons.add(addButton(i18n.getString("cancelButton"), buttonX, lineI,
254 new TAction() {
255 public void DO() {
256 result = Result.CANCEL;
257 getApplication().closeWindow(TMessageBox.this);
258 }
259 }
260 )
261 );
262 break;
263
264 case YESNO:
265 result = Result.NO;
266 if (getWidth() < 20) {
267 setWidth(20);
268 }
269 buttonX = (getWidth() - 16) / 2;
270 buttons.add(addButton(i18n.getString("yesButton"), buttonX, lineI,
271 new TAction() {
272 public void DO() {
273 result = Result.YES;
274 getApplication().closeWindow(TMessageBox.this);
275 }
276 }
277 )
278 );
279 buttonX += 5 + 4;
280 buttons.add(addButton(i18n.getString("noButton"), buttonX, lineI,
281 new TAction() {
282 public void DO() {
283 result = Result.NO;
284 getApplication().closeWindow(TMessageBox.this);
285 }
286 }
287 )
288 );
289 break;
290
291 case YESNOCANCEL:
292 result = Result.CANCEL;
293 if (getWidth() < 31) {
294 setWidth(31);
295 }
296 buttonX = (getWidth() - 27) / 2;
297 buttons.add(addButton(i18n.getString("yesButton"), buttonX, lineI,
298 new TAction() {
299 public void DO() {
300 result = Result.YES;
301 getApplication().closeWindow(TMessageBox.this);
302 }
303 }
304 )
305 );
306 buttonX += 5 + 4;
307 buttons.add(addButton(i18n.getString("noButton"), buttonX, lineI,
308 new TAction() {
309 public void DO() {
310 result = Result.NO;
311 getApplication().closeWindow(TMessageBox.this);
312 }
313 }
314 )
315 );
316 buttonX += 4 + 4;
317 buttons.add(addButton(i18n.getString("cancelButton"), buttonX,
318 lineI,
319 new TAction() {
320 public void DO() {
321 result = Result.CANCEL;
322 getApplication().closeWindow(TMessageBox.this);
323 }
324 }
325 )
326 );
327 break;
328
329 default:
330 throw new IllegalArgumentException("Invalid message box type: " + type);
331 }
332
333 // Set the secondaryThread to run me
334 getApplication().enableSecondaryEventReceiver(this);
335
336 if (yield) {
337 // Yield to the secondary thread. When I come back from the
338 // constructor response will already be set.
339 getApplication().yield();
340 }
341 }
342
343 // ------------------------------------------------------------------------
344 // TWindow ----------------------------------------------------------------
345 // ------------------------------------------------------------------------
346
347 /**
348 * Handle keystrokes.
349 *
350 * @param keypress keystroke event
351 */
352 @Override
353 public void onKeypress(final TKeypressEvent keypress) {
354
355 if (this instanceof TInputBox) {
356 super.onKeypress(keypress);
357 return;
358 }
359
360 // Some convenience for message boxes: Alt won't be needed for the
361 // buttons.
362 switch (type) {
363
364 case OK:
365 if (keypress.equals(kbO)) {
366 buttons.get(0).dispatch();
367 return;
368 }
369 break;
370
371 case OKCANCEL:
372 if (keypress.equals(kbO)) {
373 buttons.get(0).dispatch();
374 return;
375 } else if (keypress.equals(kbC)) {
376 buttons.get(1).dispatch();
377 return;
378 }
379 break;
380
381 case YESNO:
382 if (keypress.equals(kbY)) {
383 buttons.get(0).dispatch();
384 return;
385 } else if (keypress.equals(kbN)) {
386 buttons.get(1).dispatch();
387 return;
388 }
389 break;
390
391 case YESNOCANCEL:
392 if (keypress.equals(kbY)) {
393 buttons.get(0).dispatch();
394 return;
395 } else if (keypress.equals(kbN)) {
396 buttons.get(1).dispatch();
397 return;
398 } else if (keypress.equals(kbC)) {
399 buttons.get(2).dispatch();
400 return;
401 }
402 break;
403
404 default:
405 throw new IllegalArgumentException("Invalid message box type: " +
406 type);
407 }
408
409 super.onKeypress(keypress);
410 }
411
412 // ------------------------------------------------------------------------
413 // TMessageBox ------------------------------------------------------------
414 // ------------------------------------------------------------------------
415
416 /**
417 * Get the result.
418 *
419 * @return the result: OK, CANCEL, YES, or NO.
420 */
421 public final Result getResult() {
422 return result;
423 }
424
425}