Fix UTF8 bug, create first executable JAR file
[jvcard.git] / src / com / googlecode / lanterna / gui2 / SeparateTextGUIThread.java
... / ...
CommitLineData
1/*
2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
3 *
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Copyright (C) 2010-2015 Martin
18 */
19package com.googlecode.lanterna.gui2;
20
21import java.io.EOFException;
22import java.io.IOException;
23import java.util.concurrent.CountDownLatch;
24
25/**
26 * Default implementation of TextGUIThread, this class runs the GUI event processing on a dedicated thread. The GUI
27 * needs to be explicitly started in order for the event processing loop to begin, so you must call {@code start()}
28 * for this. The GUI thread will stop if {@code stop()} is called, the input stream returns EOF or an exception is
29 * thrown from inside the event handling loop.
30 * <p>
31 * Here is an example of how to use this {@code TextGUIThread}:
32 * <pre>
33 * {@code
34 * MultiWindowTextGUI textGUI = new MultiWindowTextGUI(new SeparateTextGUIThread.Factory(), screen);
35 * // ... add components ...
36 * ((AsynchronousTextGUIThread)textGUI.getGUIThread()).start();
37 * // ... this thread will continue while the GUI runs on a separate thread ...
38 * }
39 * </pre>
40 * @see TextGUIThread
41 * @see SameTextGUIThread
42 * @author Martin
43 */
44public class SeparateTextGUIThread extends AbstractTextGUIThread implements AsynchronousTextGUIThread {
45 private volatile State state;
46 private final Thread textGUIThread;
47 private final CountDownLatch waitLatch;
48
49 private SeparateTextGUIThread(TextGUI textGUI) {
50 super(textGUI);
51 this.waitLatch = new CountDownLatch(1);
52 this.textGUIThread = new Thread("LanternaGUI") {
53 @Override
54 public void run() {
55 mainGUILoop();
56 }
57 };
58 state = State.CREATED;
59 }
60
61 @Override
62 public void start() {
63 textGUIThread.start();
64 state = State.STARTED;
65 }
66
67 @Override
68 public void stop() {
69 if(state != State.STARTED) {
70 return;
71 }
72
73 state = State.STOPPING;
74 }
75
76 @Override
77 public void waitForStop() throws InterruptedException {
78 waitLatch.await();
79 }
80
81 @Override
82 public State getState() {
83 return state;
84 }
85
86 @Override
87 public Thread getThread() {
88 return textGUIThread;
89 }
90
91 @Override
92 public void invokeLater(Runnable runnable) throws IllegalStateException {
93 if(state != State.STARTED) {
94 throw new IllegalStateException("Cannot schedule " + runnable + " for execution on the TextGUIThread " +
95 "because the thread is in " + state + " state");
96 }
97 super.invokeLater(runnable);
98 }
99
100 private void mainGUILoop() {
101 try {
102 //Draw initial screen, after this only draw when the GUI is marked as invalid
103 try {
104 textGUI.updateScreen();
105 }
106 catch(IOException e) {
107 exceptionHandler.onIOException(e);
108 }
109 catch(RuntimeException e) {
110 exceptionHandler.onRuntimeException(e);
111 }
112 while(state == State.STARTED) {
113 try {
114 if (!processEventsAndUpdate()) {
115 try {
116 Thread.sleep(1);
117 }
118 catch(InterruptedException ignored) {}
119 }
120 }
121 catch(EOFException e) {
122 stop();
123 break; //Break out quickly from the main loop
124 }
125 catch(IOException e) {
126 if(exceptionHandler.onIOException(e)) {
127 stop();
128 break;
129 }
130 }
131 catch(RuntimeException e) {
132 if(exceptionHandler.onRuntimeException(e)) {
133 stop();
134 break;
135 }
136 }
137 }
138 }
139 finally {
140 state = State.STOPPED;
141 waitLatch.countDown();
142 }
143 }
144
145
146 /**
147 * Factory class for creating SeparateTextGUIThread objects
148 */
149 public static class Factory implements TextGUIThreadFactory {
150 @Override
151 public TextGUIThread createTextGUIThread(TextGUI textGUI) {
152 return new SeparateTextGUIThread(textGUI);
153 }
154 }
155}