Inceptum/launcher-gtk/src/main/java/io/gitlab/jfronny/inceptum/gtk/window/dialog/ProcessStateWatcherDialog.java

87 lines
3.3 KiB
Java

package io.gitlab.jfronny.inceptum.gtk.window.dialog;
import io.gitlab.jfronny.commons.StringFormatter;
import io.gitlab.jfronny.commons.throwable.ThrowingRunnable;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.gtk.GtkEnvBackend;
import io.gitlab.jfronny.inceptum.gtk.GtkMain;
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
import org.gtk.glib.GLib;
import org.gtk.gtk.*;
public class ProcessStateWatcherDialog extends MessageDialog {
private final ProcessState state;
private boolean finished = false;
private State cachedState = null;
public static ProcessStateWatcherDialog show(Window parent, String title, String errorMessage, ProcessState state, ThrowingRunnable<?> executor) {
ProcessStateWatcherDialog dialog = new ProcessStateWatcherDialog(parent, title, errorMessage, state, executor);
dialog.show();
return dialog;
}
public ProcessStateWatcherDialog(Window parent, String title, String errorMessage, ProcessState state, ThrowingRunnable<?> executor) {
//TODO alternate UI: Only show progress bar by default, but have a dropdown to a "console" with the actual steps
// this should make visualizing parallelized steps easier
super(parent, DialogFlags.MODAL.or(DialogFlags.DESTROY_WITH_PARENT), MessageType.INFO, ButtonsType.NONE, null);
this.state = state;
this.title = title;
addButton(I18n.get("cancel"), ResponseType.CANCEL.value);
onResponse(responseId -> {
switch (ResponseType.of(responseId)) {
case CLOSE, CANCEL -> {
state.cancel();
close();
}
case DELETE_EVENT -> destroy();
default -> Utils.LOGGER.error("Unexpected response type: " + responseId);
}
});
onCloseRequest(() -> {
if (finished) return false;
state.cancel();
return false;
});
var progress = new ProgressBar();
((Box) messageArea).append(progress);
addTickCallback((widget, clock) -> {
if (finished) return GLib.SOURCE_REMOVE;
var nc = new State(state);
if (!nc.equals(cachedState)) {
cachedState = nc;
setMarkup(cachedState.msg);
progress.fraction = Math.min(cachedState.progress, 1);
widget.queueDraw();
}
return GLib.SOURCE_CONTINUE;
}, null);
new Thread(() -> {
try {
executor.run();
} catch (Throwable e) {
state.cancel();
Utils.LOGGER.error(errorMessage, e);
GtkEnvBackend.simpleDialog(
parent,
StringFormatter.toString(e),
errorMessage,
MessageType.ERROR,
ButtonsType.CLOSE,
null,
null
);
} finally {
finished = true;
GtkMain.schedule(this::close);
}
}).start();
}
record State(String msg, float progress) {
State(ProcessState source) {
this(source.currentStep, source.progress);
}
}
}