Skip to content
Snippets Groups Projects
Commit 14d97690 authored by Petr Bainar's avatar Petr Bainar
Browse files

Fixing freezes on MacOS

parent b91b20e3
No related branches found
No related tags found
No related merge requests found
package cz.it4i.fiji.haas.ui; package cz.it4i.fiji.haas.ui;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
...@@ -62,10 +66,21 @@ public interface JavaFXRoutines { ...@@ -62,10 +66,21 @@ public interface JavaFXRoutines {
} }
static public void runOnFxThread(Runnable runnable) { static public void runOnFxThread(Runnable runnable) {
RunnableFuture<Void> task = new FutureTask<>(runnable, null);
if (Platform.isFxApplicationThread()) { if (Platform.isFxApplicationThread()) {
runnable.run(); task.run();
} else { }
Platform.runLater(runnable); else {
Platform.runLater(task);
}
try {
task.get();
}
catch (InterruptedException | ExecutionException e) {
log.error(e.getMessage(), e);
} }
} }
......
package cz.it4i.fiji.haas.ui; package cz.it4i.fiji.haas.ui;
import java.awt.Desktop; import java.awt.Desktop;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public interface ShellRoutines { public interface ShellRoutines {
public static final Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.ShellRoutines.class); public static void openDirectoryInBrowser(Path directory)
throws UnsupportedOperationException, IOException
public static void openDirectoryInBrowser(Path directory) { {
if (!Desktop.isDesktopSupported()) {
throw new UnsupportedOperationException(
"Desktop.getDesktop() is not supported on the current platform.");
}
Desktop desktop = Desktop.getDesktop(); Desktop desktop = Desktop.getDesktop();
try {
desktop.open(directory.toFile()); if (!desktop.isSupported(Desktop.Action.OPEN)) {
} catch (IOException e) { throw new UnsupportedOperationException(
log.error(e.getMessage(), e); "Desktop.open() is not supported on the current platform.");
} }
desktop.open(directory.toFile());
} }
} }
package cz.it4i.fiji.haas_spim_benchmark.commands; package cz.it4i.fiji.haas_spim_benchmark.commands;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
...@@ -27,37 +28,36 @@ import cz.it4i.fiji.haas_spim_benchmark.core.Constants; ...@@ -27,37 +28,36 @@ import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
import cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMWindow; import cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMWindow;
/** /**
*
* @author koz01 * @author koz01
*
*/ */
@Plugin(type = Command.class, headless = false, menuPath = "Plugins>" + Constants.MENU_ITEM_NAME + ">" + Constants.SUBMENU_ITEM_NAME) @Plugin(type = Command.class, headless = false, menuPath = "Plugins>" +
Constants.MENU_ITEM_NAME + ">" + Constants.SUBMENU_ITEM_NAME)
public class ManageSPIMBenchmark implements Command { public class ManageSPIMBenchmark implements Command {
private static Logger log = LoggerFactory private static Logger log = LoggerFactory.getLogger(
.getLogger(cz.it4i.fiji.haas_spim_benchmark.commands.ManageSPIMBenchmark.class); cz.it4i.fiji.haas_spim_benchmark.commands.ManageSPIMBenchmark.class);
private static final String LOCK_FILE_NAME = ".lock"; private static final String LOCK_FILE_NAME = ".lock";
@Parameter @Parameter
private UIService uiService; private UIService uiService;
@Parameter @Parameter
private Context context; private Context context;
@Parameter(style = TextWidget.FIELD_STYLE, label = "User name") @Parameter(style = TextWidget.FIELD_STYLE, label = "User name")
private String userName; private String userName;
@Parameter(style = TextWidget.PASSWORD_STYLE) @Parameter(style = TextWidget.PASSWORD_STYLE)
private String password; private String password;
@Parameter(style = TextWidget.FIELD_STYLE) @Parameter(style = TextWidget.FIELD_STYLE)
private String email; private String email;
@Parameter(label = "Working directory", persist = true, style = FileWidget.DIRECTORY_STYLE) @Parameter(label = "Working directory", persist = true,
style = FileWidget.DIRECTORY_STYLE)
private File workingDirectory; private File workingDirectory;
@Override @Override
public void run() { public void run() {
try { try {
...@@ -67,16 +67,20 @@ public class ManageSPIMBenchmark implements Command { ...@@ -67,16 +67,20 @@ public class ManageSPIMBenchmark implements Command {
} }
@SuppressWarnings("resource") @SuppressWarnings("resource")
final FileLock fl = new FileLock(workingDirPath.resolve(LOCK_FILE_NAME)); final FileLock fl = new FileLock(workingDirPath.resolve(LOCK_FILE_NAME));
if(!fl.tryLock()) { if (!fl.tryLock()) {
uiService.showDialog("Working directory is already used by someone else", MessageType.ERROR_MESSAGE); uiService.showDialog(
"Working directory is already used by someone else",
MessageType.ERROR_MESSAGE);
return; return;
} }
final BenchmarkSPIMWindow dialog = new BenchmarkSPIMWindow(null, final BenchmarkSPIMWindow dialog = new BenchmarkSPIMWindow(null,
new BenchmarkSPIMParametersImpl(userName, password, Constants.PHONE, email, workingDirPath)); new BenchmarkSPIMParametersImpl(userName, password, Constants.PHONE,
email, workingDirPath));
dialog.executeAdjustment(() -> { dialog.executeAdjustment(() -> {
dialog.setTitle(Constants.SUBMENU_ITEM_NAME); dialog.setTitle(Constants.SUBMENU_ITEM_NAME);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() { dialog.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing(final WindowEvent e) { public void windowClosing(final WindowEvent e) {
super.windowClosing(e); super.windowClosing(e);
...@@ -85,7 +89,8 @@ public class ManageSPIMBenchmark implements Command { ...@@ -85,7 +89,8 @@ public class ManageSPIMBenchmark implements Command {
}); });
dialog.setVisible(true); dialog.setVisible(true);
}); });
} catch (final IOException e) { }
catch (final IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
......
package cz.it4i.fiji.haas_spim_benchmark.core; package cz.it4i.fiji.haas_spim_benchmark.core;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import cz.it4i.fiji.haas.ui.JavaFXRoutines; import cz.it4i.fiji.haas.ui.JavaFXRoutines;
public class FXFrameExecutorService implements Executor{ public class FXFrameExecutorService implements Executor {
@Override @Override
public void execute(Runnable command) { public void execute(Runnable command) {
JavaFXRoutines.runOnFxThread(() -> { JavaFXRoutines.runOnFxThread(() -> {
command.run(); command.run();
}); });
} }
} }
...@@ -65,20 +65,23 @@ import javafx.scene.layout.BorderPane; ...@@ -65,20 +65,23 @@ import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region; import javafx.scene.layout.Region;
import mpicbg.spim.data.SpimDataException; import mpicbg.spim.data.SpimDataException;
public class BenchmarkSPIMControl extends BorderPane implements CloseableControl, InitiableControl { public class BenchmarkSPIMControl extends BorderPane implements
CloseableControl, InitiableControl
{
@FXML @FXML
private TableView<ObservableBenchmarkJob> jobs; private TableView<ObservableBenchmarkJob> jobs;
private final BenchmarkJobManager manager; private final BenchmarkJobManager manager;
private final ExecutorService executorServiceJobState = Executors.newWorkStealingPool(); private final ExecutorService executorServiceJobState = Executors
.newWorkStealingPool();
private final Executor executorServiceFX = new FXFrameExecutorService(); private final Executor executorServiceFX = new FXFrameExecutorService();
private Window root; private Window root;
private ExecutorService executorServiceUI; private ExecutorService executorServiceShell;
private ExecutorService executorServiceWS; private ExecutorService executorServiceWS;
...@@ -88,21 +91,22 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -88,21 +91,22 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
private final JobStateNameProvider provider = new JobStateNameProvider(); private final JobStateNameProvider provider = new JobStateNameProvider();
private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMControl.class); private static Logger log = LoggerFactory.getLogger(
cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMControl.class);
public BenchmarkSPIMControl(BenchmarkJobManager manager) { public BenchmarkSPIMControl(BenchmarkJobManager manager) {
this.manager = manager; this.manager = manager;
JavaFXRoutines.initRootAndController("BenchmarkSPIM.fxml", this); JavaFXRoutines.initRootAndController("BenchmarkSPIM.fxml", this);
} }
@Override @Override
public void init(Window rootWindow) { public void init(Window rootWindow) {
this.root = rootWindow; this.root = rootWindow;
executorServiceWS = Executors.newSingleThreadExecutor(); executorServiceWS = Executors.newSingleThreadExecutor();
executorServiceUI = Executors.newSingleThreadExecutor(); executorServiceShell = Executors.newSingleThreadExecutor();
timer = new Timer(); timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() {
@Override @Override
public void run() { public void run() {
updateJobs(false); updateJobs(false);
...@@ -110,12 +114,12 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -110,12 +114,12 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
}, Constants.HAAS_UPDATE_TIMEOUT, Constants.HAAS_UPDATE_TIMEOUT); }, Constants.HAAS_UPDATE_TIMEOUT, Constants.HAAS_UPDATE_TIMEOUT);
initTable(); initTable();
initMenu(); initMenu();
executorServiceFX.execute(this::updateJobs); executorServiceFX.execute(() -> updateJobs(true));
} }
@Override @Override
public void close() { public void close() {
executorServiceUI.shutdown(); executorServiceShell.shutdown();
executorServiceWS.shutdown(); executorServiceWS.shutdown();
executorServiceJobState.shutdown(); executorServiceJobState.shutdown();
timer.cancel(); timer.cancel();
...@@ -123,51 +127,55 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -123,51 +127,55 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
} }
private void initMenu() { private void initMenu() {
TableViewContextMenu<ObservableBenchmarkJob> menu = new TableViewContextMenu<>(jobs); TableViewContextMenu<ObservableBenchmarkJob> menu =
new TableViewContextMenu<>(jobs);
menu.addItem("Create a new job", x -> askForCreateJob(), j -> true); menu.addItem("Create a new job", x -> askForCreateJob(), j -> true);
menu.addSeparator(); menu.addSeparator();
menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> { menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> {
job.getValue().startJob(p); job.getValue().startJob(p);
job.getValue().update(); job.getValue().update();
}), job -> JavaFXRoutines.notNullValue(job, }), job -> JavaFXRoutines.notNullValue(job, j -> j
j -> j.getState() == JobState.Configuring || j.getState() == JobState.Finished .getState() == JobState.Configuring || j
|| j.getState() == JobState.Failed || j.getState() == JobState.Canceled)); .getState() == JobState.Finished || j.getState() == JobState.Failed || j
.getState() == JobState.Canceled));
menu.addItem("Cancel job", job -> executeWSCallAsync("Canceling job", p -> { menu.addItem("Cancel job", job -> executeWSCallAsync("Canceling job", p -> {
job.getValue().cancelJob(); job.getValue().cancelJob();
job.getValue().update(); job.getValue().update();
}), job -> JavaFXRoutines.notNullValue(job, }), job -> JavaFXRoutines.notNullValue(job, j -> j
j -> j.getState() == JobState.Running || j.getState() == JobState.Queued)); .getState() == JobState.Running || j.getState() == JobState.Queued));
menu.addItem("Job dashboard", job -> openJobDetailsWindow(job.getValue()), menu.addItem("Job dashboard", job -> openJobDetailsWindow(job.getValue()),
job -> JavaFXRoutines.notNullValue(job, j -> true)); job -> JavaFXRoutines.notNullValue(job, j -> true));
menu.addItem("Open job subdirectory", j -> open(j.getValue()), x -> JavaFXRoutines.notNullValue(x, j -> true)); menu.addItem("Open job subdirectory", j -> openJobSubdirectory(j
.getValue()), x -> JavaFXRoutines.notNullValue(x, j -> true));
menu.addItem("Open in BigDataViewer", j -> openBigDataViewer(j.getValue()), menu.addItem("Open in BigDataViewer", j -> openBigDataViewer(j.getValue()),
x -> JavaFXRoutines.notNullValue(x, j -> true)); x -> JavaFXRoutines.notNullValue(x, j -> true));
menu.addSeparator(); menu.addSeparator();
menu.addItem("Upload data", job -> executeWSCallAsync("Uploading data", p -> job.getValue().startUpload()), menu.addItem("Upload data", job -> executeWSCallAsync("Uploading data",
job -> executeWSCallAsync("Stop uploading data", p -> job.getValue().stopUpload()), p -> job.getValue().startUpload()), job -> executeWSCallAsync(
job -> JavaFXRoutines.notNullValue(job, "Stop uploading data", p -> job.getValue().stopUpload()),
j -> !j.isUseDemoData() job -> JavaFXRoutines.notNullValue(job, j -> !j.isUseDemoData() &&
&& !EnumSet.of(JobState.Running, JobState.Disposed).contains(j.getState())), !EnumSet.of(JobState.Running, JobState.Disposed).contains(j
job -> job != null && job.getUploadProgress().isWorking()); .getState())), job -> job != null && job.getUploadProgress()
menu.addItem("Download result", .isWorking());
job -> executeWSCallAsync("Downloading data", p -> job.getValue().startDownload()), menu.addItem("Download result", job -> executeWSCallAsync(
job -> executeWSCallAsync("Stop downloading data", p -> job.getValue().stopDownload()), "Downloading data", p -> job.getValue().startDownload()),
job -> JavaFXRoutines job -> executeWSCallAsync("Stop downloading data", p -> job.getValue()
.notNullValue(job, .stopDownload()), job -> JavaFXRoutines.notNullValue(job, j -> EnumSet
j -> EnumSet.of(JobState.Failed, JobState.Finished, JobState.Canceled) .of(JobState.Failed, JobState.Finished, JobState.Canceled).contains(j
.contains(j.getState()) && j.canBeDownloaded()), .getState()) && j.canBeDownloaded()), job -> job != null && job
job -> job != null && job.getDownloadProgress().isWorking()); .getDownloadProgress().isWorking());
menu.addItem("Explore errors", job -> job.getValue().exploreErrors(), menu.addItem("Explore errors", job -> job.getValue().exploreErrors(),
job -> JavaFXRoutines.notNullValue(job, j -> j.getState().equals(JobState.Failed))); job -> JavaFXRoutines.notNullValue(job, j -> j.getState().equals(
JobState.Failed)));
menu.addSeparator(); menu.addSeparator();
menu.addItem("Delete job", j -> deleteJob(j.getValue()), menu.addItem("Delete job", j -> deleteJob(j.getValue()), x -> JavaFXRoutines
x -> JavaFXRoutines.notNullValue(x, j -> j.getState() != JobState.Running)); .notNullValue(x, j -> j.getState() != JobState.Running));
} }
...@@ -179,42 +187,47 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -179,42 +187,47 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
private void askForCreateJob() { private void askForCreateJob() {
NewJobWindow newJobWindow = new NewJobWindow(null); NewJobWindow newJobWindow = new NewJobWindow(null);
ModalDialogs.doModal(newJobWindow, WindowConstants.DISPOSE_ON_CLOSE); ModalDialogs.doModal(newJobWindow, WindowConstants.DISPOSE_ON_CLOSE);
newJobWindow.setCreatePressedNotifier(() -> executeWSCallAsync("Creating job", false, new P_JobAction() { newJobWindow.setCreatePressedNotifier(() -> executeWSCallAsync(
@Override "Creating job", false, new P_JobAction()
public void doAction(Progress p) throws IOException { {
BenchmarkJob job = doCreateJob(wd -> newJobWindow.getInputDirectory(wd),
wd -> newJobWindow.getOutputDirectory(wd)); @Override
if (job.isUseDemoData()) { public void doAction(Progress p) throws IOException {
job.storeDataInWorkdirectory(getConfigYamlFile()); BenchmarkJob job = doCreateJob(wd -> newJobWindow.getInputDirectory(
} else if (Files.exists(job.getInputDirectory().resolve(CONFIG_YAML))) { wd), wd -> newJobWindow.getOutputDirectory(wd));
executorServiceFX.execute(new Runnable() { if (job.isUseDemoData()) {
job.storeDataInWorkdirectory(getConfigYamlFile());
@Override }
public void run() { else if (Files.exists(job.getInputDirectory().resolve(CONFIG_YAML))) {
Alert al = new Alert(AlertType.CONFIRMATION, executorServiceFX.execute(new Runnable() {
"The file \"" + CONFIG_YAML + "\" found in the defined data input directory \""
+ job.getInputDirectory() @Override
+ "\". Would you like to copy it into the job working directory \"" public void run() {
+ job.getDirectory() + "\"?", Alert al = new Alert(AlertType.CONFIRMATION, "The file \"" +
ButtonType.YES, ButtonType.NO); CONFIG_YAML +
"\" found in the defined data input directory \"" + job
al.setHeaderText(null); .getInputDirectory() +
al.setTitle("Copy " + CONFIG_YAML + "?"); "\". Would you like to copy it into the job working directory \"" +
al.getDialogPane().setMinHeight(Region.USE_PREF_SIZE); job.getDirectory() + "\"?", ButtonType.YES, ButtonType.NO);
if (al.showAndWait().get() == ButtonType.YES) {
try { al.setHeaderText(null);
Files.copy(job.getInputDirectory().resolve(CONFIG_YAML), al.setTitle("Copy " + CONFIG_YAML + "?");
job.getDirectory().resolve(CONFIG_YAML)); al.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
} catch (IOException e) { if (al.showAndWait().get() == ButtonType.YES) {
log.error(e.getMessage(), e); try {
Files.copy(job.getInputDirectory().resolve(CONFIG_YAML), job
.getDirectory().resolve(CONFIG_YAML));
}
catch (IOException e) {
log.error(e.getMessage(), e);
}
} }
} }
} });
});
}
} }
} }));
}));
} }
...@@ -222,8 +235,9 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -222,8 +235,9 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
return new UploadingFileFromResource("", Constants.CONFIG_YAML); return new UploadingFileFromResource("", Constants.CONFIG_YAML);
} }
private BenchmarkJob doCreateJob(Function<Path, Path> inputProvider, Function<Path, Path> outputProvider) private BenchmarkJob doCreateJob(Function<Path, Path> inputProvider,
throws IOException { Function<Path, Path> outputProvider) throws IOException
{
BenchmarkJob bj = manager.createJob(inputProvider, outputProvider); BenchmarkJob bj = manager.createJob(inputProvider, outputProvider);
ObservableBenchmarkJob obj = registry.addIfAbsent(bj); ObservableBenchmarkJob obj = registry.addIfAbsent(bj);
addJobToItems(obj); addJobToItems(obj);
...@@ -235,9 +249,15 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -235,9 +249,15 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
jobs.getItems().add(obj); jobs.getItems().add(obj);
} }
private void open(BenchmarkJob j) { private void openJobSubdirectory(BenchmarkJob j) {
executorServiceUI.execute(() -> { executorServiceShell.execute(() -> {
ShellRoutines.openDirectoryInBrowser(j.getDirectory()); try {
ShellRoutines.openDirectoryInBrowser(j.getDirectory());
}
catch (UnsupportedOperationException | IOException e) {
// TODO: Escalate an error to the end user
log.error(e.getMessage(), e);
}
}); });
} }
...@@ -245,34 +265,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -245,34 +265,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
executeWSCallAsync(title, true, action); executeWSCallAsync(title, true, action);
} }
private void executeWSCallAsync(String title, boolean update, P_JobAction action) { private void executeWSCallAsync(String title, boolean update,
P_JobAction action)
{
JavaFXRoutines.executeAsync(executorServiceWS, (Callable<Void>) () -> { JavaFXRoutines.executeAsync(executorServiceWS, (Callable<Void>) () -> {
ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(root, title), ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(root,
WindowConstants.DO_NOTHING_ON_CLOSE); title), WindowConstants.DO_NOTHING_ON_CLOSE);
try { try {
action.doAction(dialog); action.doAction(dialog);
} finally { }
finally {
dialog.done(); dialog.done();
} }
return null; return null;
}, x -> { }, x -> {
if (update) { if (update) {
updateJobs(); updateJobs(true);
} }
}); });
} }
private void updateJobs() {
updateJobs(true);
}
private void updateJobs(boolean showProgress) { private void updateJobs(boolean showProgress) {
if (manager == null) { if (manager == null) {
return; return;
} }
Progress progress = showProgress Progress progress = showProgress ? ModalDialogs.doModal(new ProgressDialog(
? ModalDialogs.doModal(new ProgressDialog(root, "Updating jobs"), WindowConstants.DO_NOTHING_ON_CLOSE) root, "Updating jobs"), WindowConstants.DO_NOTHING_ON_CLOSE)
: new DummyProgress(); : new DummyProgress();
executorServiceWS.execute(() -> { executorServiceWS.execute(() -> {
List<BenchmarkJob> inspectedJobs = new LinkedList<>(manager.getJobs()); List<BenchmarkJob> inspectedJobs = new LinkedList<>(manager.getJobs());
...@@ -281,7 +300,8 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -281,7 +300,8 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
registry.addIfAbsent(bj); registry.addIfAbsent(bj);
} }
registry.update(); registry.update();
Set<ObservableValue<BenchmarkJob>> actual = new HashSet<>(this.jobs.getItems()); Set<ObservableValue<BenchmarkJob>> actual = new HashSet<>(this.jobs
.getItems());
executorServiceFX.execute(() -> { executorServiceFX.execute(() -> {
for (ObservableBenchmarkJob value : registry.getAllItems()) { for (ObservableBenchmarkJob value : registry.getAllItems()) {
...@@ -295,26 +315,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -295,26 +315,33 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
} }
private void initTable() { private void initTable() {
registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj), executorServiceJobState, executorServiceFX); registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj),
executorServiceJobState, executorServiceFX);
setCellValueFactory(0, j -> j.getId() + ""); setCellValueFactory(0, j -> j.getId() + "");
setCellValueFactoryCompletable(1, setCellValueFactoryCompletable(1, j -> j.getStateAsync(
j -> j.getStateAsync(executorServiceJobState).thenApply(state -> "" + provider.getName(state))); executorServiceJobState).thenApply(state -> "" + provider.getName(
state)));
setCellValueFactory(2, j -> j.getCreationTime().toString()); setCellValueFactory(2, j -> j.getCreationTime().toString());
setCellValueFactory(3, j -> j.getStartTime().toString()); setCellValueFactory(3, j -> j.getStartTime().toString());
setCellValueFactory(4, j -> j.getEndTime().toString()); setCellValueFactory(4, j -> j.getEndTime().toString());
setCellValueFactory(5, j -> decorateTransfer(registry.get(j).getUploadProgress())); setCellValueFactory(5, j -> decorateTransfer(registry.get(j)
setCellValueFactory(6, j -> decorateTransfer(registry.get(j).getDownloadProgress())); .getUploadProgress()));
JavaFXRoutines.setOnDoubleClickAction(jobs, executorServiceJobState, openJobDetailsWindow -> true, setCellValueFactory(6, j -> decorateTransfer(registry.get(j)
bj -> openJobDetailsWindow(bj)); .getDownloadProgress()));
JavaFXRoutines.setOnDoubleClickAction(jobs, executorServiceJobState,
openJobDetailsWindow -> true, bj -> openJobDetailsWindow(bj));
} }
private String decorateTransfer(TransferProgress progress) { private String decorateTransfer(TransferProgress progress) {
if (!progress.isWorking() && !progress.isDone()) { if (!progress.isWorking() && !progress.isDone()) {
return ""; return "";
} else if (progress.isWorking()) { }
else if (progress.isWorking()) {
Long msecs = progress.getRemainingMiliseconds(); Long msecs = progress.getRemainingMiliseconds();
return "Time remains " + (msecs != null ? RemainingTimeFormater.format(msecs) : "N/A"); return "Time remains " + (msecs != null ? RemainingTimeFormater.format(
} else if (progress.isDone()) { msecs) : "N/A");
}
else if (progress.isDone()) {
return "Done"; return "Done";
} }
return "N/A"; return "N/A";
...@@ -324,23 +351,27 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -324,23 +351,27 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
jobs.getItems().remove(registry.get(bj)); jobs.getItems().remove(registry.get(bj));
} }
private void setCellValueFactory(int index, Function<BenchmarkJob, String> mapper) { private void setCellValueFactory(int index,
Function<BenchmarkJob, String> mapper)
{
JavaFXRoutines.setCellValueFactory(jobs, index, mapper); JavaFXRoutines.setCellValueFactory(jobs, index, mapper);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void setCellValueFactoryCompletable(int index, Function<BenchmarkJob, CompletableFuture<String>> mapper) { private void setCellValueFactoryCompletable(int index,
Function<BenchmarkJob, CompletableFuture<String>> mapper)
{
JavaFXRoutines.setCellValueFactory(jobs, index, mapper); JavaFXRoutines.setCellValueFactory(jobs, index, mapper);
((TableColumn<ObservableBenchmarkJob, CompletableFuture<String>>) jobs.getColumns().get(index)) ((TableColumn<ObservableBenchmarkJob, CompletableFuture<String>>) jobs
.setCellFactory(column -> new TableCellAdapter<> // .getColumns().get(index)).setCellFactory(column -> new TableCellAdapter<> //
(//
new P_TableCellUpdaterDecoratorWithToolTip<>//
(//
new FutureValueUpdater<>//
(// (//
new P_TableCellUpdaterDecoratorWithToolTip<>// new StringValueUpdater<ObservableBenchmarkJob>(), executorServiceFX//
(// ), //
new FutureValueUpdater<>// "Doubleclick to open Dashboard")));
(//
new StringValueUpdater<ObservableBenchmarkJob>(), executorServiceFX//
), //
"Doubleclick to open Dashboard")));
} }
private void openJobDetailsWindow(BenchmarkJob job) { private void openJobDetailsWindow(BenchmarkJob job) {
...@@ -353,33 +384,41 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl ...@@ -353,33 +384,41 @@ public class BenchmarkSPIMControl extends BorderPane implements CloseableControl
String openFile; String openFile;
if (Files.exists(localPathToResultXML)) { if (Files.exists(localPathToResultXML)) {
openFile = localPathToResultXML.toString(); openFile = localPathToResultXML.toString();
} else { }
else {
openFile = startBDSForData(job, resultXML); openFile = startBDSForData(job, resultXML);
} }
try { try {
BigDataViewer.open(openFile, "Result of job " + job.getId(), new ProgressWriterConsole(), BigDataViewer.open(openFile, "Result of job " + job.getId(),
ViewerOptions.options()); new ProgressWriterConsole(), ViewerOptions.options());
} catch (SpimDataException e) { }
catch (SpimDataException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }
} }
private String startBDSForData(BenchmarkJob job, Path resultXML) { private String startBDSForData(BenchmarkJob job, Path resultXML) {
throw new UnsupportedOperationException("File " + resultXML + " was not found in " + job.getOutputDirectory() throw new UnsupportedOperationException("File " + resultXML +
+ " and remote BigDataServer is not implemented yet."); " was not found in " + job.getOutputDirectory() +
" and remote BigDataServer is not implemented yet.");
} }
private interface P_JobAction { private interface P_JobAction {
public void doAction(Progress p) throws IOException; public void doAction(Progress p) throws IOException;
} }
private class P_TableCellUpdaterDecoratorWithToolTip<S, T> implements TableCellUpdater<S, T> { private class P_TableCellUpdaterDecoratorWithToolTip<S, T> implements
TableCellUpdater<S, T>
{
private final TableCellUpdater<S, T> decorated; private final TableCellUpdater<S, T> decorated;
private final String toolTipText; private final String toolTipText;
public P_TableCellUpdaterDecoratorWithToolTip(TableCellUpdater<S, T> decorated, String toolTipText) { public P_TableCellUpdaterDecoratorWithToolTip(
TableCellUpdater<S, T> decorated, String toolTipText)
{
this.decorated = decorated; this.decorated = decorated;
this.toolTipText = toolTipText; this.toolTipText = toolTipText;
} }
......
package cz.it4i.fiji.haas_spim_benchmark.ui; package cz.it4i.fiji.haas_spim_benchmark.ui;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
...@@ -51,8 +52,16 @@ public class JobPropertiesControl extends BorderPane implements Closeable { ...@@ -51,8 +52,16 @@ public class JobPropertiesControl extends BorderPane implements Closeable {
private void initTable() { private void initTable() {
setCellValueFactory(0, s -> s.getName()); setCellValueFactory(0, s -> s.getName());
setCellValueFactory(1, s -> s.getValueAsString()); setCellValueFactory(1, s -> s.getValueAsString());
JavaFXRoutines.setOnDoubleClickAction(properties, executorServiceUI, rowData -> rowData.isOpenAllowed(), JavaFXRoutines.setOnDoubleClickAction(properties, executorServiceUI,
rowData -> ShellRoutines.openDirectoryInBrowser(rowData.getPath())); rowData -> rowData.isOpenAllowed(), rowData -> {
try {
ShellRoutines.openDirectoryInBrowser(rowData.getPath());
}
catch (UnsupportedOperationException | IOException e) {
// TODO: Escalate an error to the end user
log.error(e.getMessage(), e);
}
});
} }
private void fillTable() { private void fillTable() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment