/*
* This file is part of lanterna (https://github.com/mabe02/lanterna).
*
* lanterna is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2010-2020 Martin Berglund
*/
package com.googlecode.lanterna.gui2;
import java.io.EOFException;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
Abstract implementation of TextGUIThread
with common logic for both available concrete implementations. /**
* Abstract implementation of {@link TextGUIThread} with common logic for both available concrete implementations.
*/
public abstract class AbstractTextGUIThread implements TextGUIThread {
protected final TextGUI textGUI;
protected final Queue<Runnable> customTasks;
protected ExceptionHandler exceptionHandler;
Sets up this AbstractTextGUIThread
for operations on the supplies TextGUI
Params: - textGUI – Text GUI this
TextGUIThread
implementations will be operating on
/**
* Sets up this {@link AbstractTextGUIThread} for operations on the supplies {@link TextGUI}
* @param textGUI Text GUI this {@link TextGUIThread} implementations will be operating on
*/
public AbstractTextGUIThread(TextGUI textGUI) {
this.exceptionHandler = new ExceptionHandler() {
@Override
public boolean onIOException(IOException e) {
e.printStackTrace();
return true;
}
@Override
public boolean onRuntimeException(RuntimeException e) {
e.printStackTrace();
return true;
}
};
this.textGUI = textGUI;
this.customTasks = new LinkedBlockingQueue<>();
}
@Override
public void invokeLater(Runnable runnable) throws IllegalStateException {
customTasks.add(runnable);
}
@Override
public void setExceptionHandler(ExceptionHandler exceptionHandler) {
if(exceptionHandler == null) {
throw new IllegalArgumentException("Cannot call setExceptionHandler(null)");
}
this.exceptionHandler = exceptionHandler;
}
@Override
public synchronized boolean processEventsAndUpdate() throws IOException {
if(getThread() != Thread.currentThread()) {
throw new IllegalStateException("Calling processEventAndUpdate outside of GUI thread");
}
try {
textGUI.processInput();
while (!customTasks.isEmpty()) {
Runnable r = customTasks.poll();
if (r != null) {
r.run();
}
}
if (textGUI.isPendingUpdate()) {
textGUI.updateScreen();
return true;
}
return false;
}
catch (EOFException e) {
// Always re-throw EOFExceptions so the UI system knows we've closed the terminal
throw e;
}
catch (IOException e) {
if (exceptionHandler != null) {
exceptionHandler.onIOException(e);
}
else {
throw e;
}
}
catch (RuntimeException e) {
if (exceptionHandler != null) {
exceptionHandler.onRuntimeException(e);
}
else {
throw e;
}
}
return true;
}
@Override
public void invokeAndWait(final Runnable runnable) throws IllegalStateException, InterruptedException {
Thread guiThread = getThread();
if(guiThread == null || Thread.currentThread() == guiThread) {
runnable.run();
}
else {
final CountDownLatch countDownLatch = new CountDownLatch(1);
invokeLater(() -> {
try {
runnable.run();
}
finally {
countDownLatch.countDown();
}
});
countDownLatch.await();
}
}
}