From 1aa5ced84484d79d5158115369d337cca61843a7 Mon Sep 17 00:00:00 2001 From: Jan Kozusznik <jan@kozusznik.cz> Date: Tue, 30 Jan 2018 15:37:31 +0100 Subject: [PATCH] improve updateble values --- .../java/cz/it4i/fiji/haas/ui/FXFrame.java | 30 +++++- .../fiji/haas/ui/ObservableValueRegistry.java | 44 +++++++++ .../haas/ui/UpdatableObservableValue.java | 37 +++++++ .../fiji/haas_spim_benchmark/core/Task.java | 11 ++- .../core/TaskComputation.java | 9 ++ .../ui/BenchmarkSPIMController.java | 48 ++++----- .../ui/ObservableTaskRegistry.java | 30 ++++++ .../ui/SPIMPipelineProgressView.fxml | 15 +++ .../SPIMPipelineProgressViewController.java | 97 +++++++++++++++++++ .../ui/SPIMPipelineProgressViewWindow.java | 19 ++++ .../it4i/fiji/haas/RunSPIMPipelineView.java | 14 +++ 11 files changed, 320 insertions(+), 34 deletions(-) create mode 100644 haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java create mode 100644 haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java create mode 100644 haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/ObservableTaskRegistry.java create mode 100644 haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml create mode 100644 haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java create mode 100644 haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewWindow.java create mode 100644 haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java index a91f5d56..47b16deb 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java @@ -2,12 +2,14 @@ package cz.it4i.fiji.haas.ui; import java.awt.BorderLayout; import java.awt.Dimension; -import java.awt.Frame; import java.awt.Window; import java.awt.im.InputMethodRequests; import java.io.IOException; import java.net.URL; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.function.Function; import javax.swing.JDialog; import javax.swing.JScrollPane; @@ -16,10 +18,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javafx.application.Platform; +import javafx.beans.value.ObservableValue; import javafx.embed.swing.JFXPanel; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; public class FXFrame<C extends FXFrame.Controller> extends JDialog { @@ -36,6 +41,25 @@ public class FXFrame<C extends FXFrame.Controller> extends JDialog { public interface Controller { void init(Window frame); + static public <V> void executeAsync(Executor executor, Callable<V> action, Consumer<V> postAction) { + executor.execute(() -> { + V result; + try { + result = action.call(); + postAction.accept(result); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + + }); + } + + @SuppressWarnings("unchecked") + static public <U,T extends ObservableValue<U>> void setCellValueFactory(TableView<T> tableView,int index, Function<U, String> mapper) { + ((TableColumn<T, String>) tableView.getColumns().get(index)) + .setCellValueFactory(f -> new ObservableValueAdapter<U, String>(f.getValue(), mapper)); + + } } private static final long serialVersionUID = 1L; @@ -48,8 +72,8 @@ public class FXFrame<C extends FXFrame.Controller> extends JDialog { this(null, fxmlFile); } - public FXFrame(Frame applicationFrame, String string) { - super(applicationFrame); + public FXFrame(Window applicationFrame, String string) { + super(applicationFrame,ModalityType.MODELESS); fxmlFile = string; } diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java new file mode 100644 index 00000000..d210a4f4 --- /dev/null +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java @@ -0,0 +1,44 @@ +package cz.it4i.fiji.haas.ui; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; + +import javafx.beans.value.ObservableValue; + +public class ObservableValueRegistry<T> { + + private Function<T, Boolean> updateFunction; + private Function<T, Boolean> validateFunction; + private Consumer<T> removeConsumer; + + + public ObservableValueRegistry(Function<T, Boolean> validateFunction, Function<T, Boolean> updateFunction, + Consumer<T> removeConsumer) { + super(); + this.validateFunction = validateFunction; + this.updateFunction = updateFunction; + this.removeConsumer = removeConsumer; + } + + private Map<T,UpdatableObservableValue<T>> map = new HashMap<>(); + + public ObservableValue<T> addIfAbsent(T value) { + UpdatableObservableValue<T> uov = map.computeIfAbsent(value, v-> new UpdatableObservableValue<T>(v, updateFunction, validateFunction)); + return uov; + } + + public ObservableValue<T> remove(T value) { + return map.get(value); + } + + public void update() { + for (UpdatableObservableValue<T> value : new LinkedList<>(map.values())) { + if(!value.update()) { + removeConsumer.accept(value.getValue()); + } + } + } +} diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java new file mode 100644 index 00000000..3bd8930d --- /dev/null +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java @@ -0,0 +1,37 @@ +package cz.it4i.fiji.haas.ui; + +import java.util.function.Function; + +import javafx.beans.value.ObservableValueBase; + +public class UpdatableObservableValue<T> extends ObservableValueBase<T>{ + + private T wrapped; + private Function<T,Boolean> updateFunction; + private Function<T,Boolean> validateFunction; + + + public UpdatableObservableValue(T wrapped, Function<T, Boolean> updateFunction, Function<T, Boolean> validateFunction) { + super(); + this.wrapped = wrapped; + this.updateFunction = updateFunction; + this.validateFunction = validateFunction; + } + + @Override + public T getValue() { + + return wrapped; + } + + public boolean update() { + if(!validateFunction.apply(wrapped)) { + return false; + } + if(updateFunction.apply(wrapped)) { + fireValueChangedEvent(); + } + return true; + } + +} diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Task.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Task.java index 84af6203..285a579f 100644 --- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Task.java +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Task.java @@ -1,12 +1,12 @@ package cz.it4i.fiji.haas_spim_benchmark.core; -import java.util.Collection; import java.util.LinkedList; +import java.util.List; public class Task { private SPIMComputationAccessor outputHolder; private String description; - private Collection<TaskComputation> computations; + private List<TaskComputation> computations; private int numComputations; public Task(SPIMComputationAccessor outputHolder, String description, int numComputations) { @@ -15,7 +15,7 @@ public class Task { this.numComputations = numComputations; } - public Collection<TaskComputation> getComputations() { + public List<TaskComputation> getComputations() { if (computations == null) { fillComputations(); } @@ -33,4 +33,9 @@ public class Task { } } + public void update() { + // TODO Auto-generated method stub + + } + } diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java index 2d1c7b22..c0fc812c 100644 --- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java @@ -29,6 +29,10 @@ public class TaskComputation { updateState();//TASK 1011 it is not good idea update every time when state is requested return state != null?state:JobState.Configuring; } + + public int getTimepoint() { + return timepoint; + } private void updateState() { String snakeOutput = outputHolder.getActualOutput(); @@ -65,5 +69,10 @@ public class TaskComputation { // //or return } + + public void update() { + // TODO Auto-generated method stub + + } } diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java index 74097b09..cd35978f 100644 --- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java @@ -15,7 +15,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -28,7 +27,6 @@ import org.slf4j.LoggerFactory; import cz.it4i.fiji.haas.ui.DummyProgress; import cz.it4i.fiji.haas.ui.FXFrame; import cz.it4i.fiji.haas.ui.ModalDialogs; -import cz.it4i.fiji.haas.ui.ObservableValueAdapter; import cz.it4i.fiji.haas.ui.ProgressDialog; import cz.it4i.fiji.haas.ui.TableViewContextMenu; import cz.it4i.fiji.haas_java_client.JobState; @@ -37,7 +35,6 @@ import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob; import cz.it4i.fiji.haas_spim_benchmark.core.Constants; import cz.it4i.fiji.haas_spim_benchmark.core.FXFrameExecutorService; import javafx.fxml.FXML; -import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import net.imagej.updater.util.Progress; @@ -98,11 +95,21 @@ public class BenchmarkSPIMController implements FXFrame.Controller { private void initMenu() { TableViewContextMenu<BenchmarkJob> menu = new TableViewContextMenu<>(jobs); - menu.addItem("Create job", x -> executeWSCallAsync("Creating job", p -> manager.createJob()), - j -> true); + menu.addItem("Create job", x -> executeWSCallAsync("Creating job", p -> manager.createJob()), j -> true); menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> job.startJob(p)), job -> notNullValue(job, j -> j.getState() == JobState.Configuring || j.getState() == JobState.Finished)); + + menu.addItem("Show progress", job -> { + try { + new SPIMPipelineProgressViewWindow(root, job).setVisible(true); + } catch (IOException e) { + // TODO Auto-generated catch block + log.error(e.getMessage(), e); + } + }, job -> notNullValue(job, j -> j.getState() == JobState.Running || j.getState() == JobState.Finished + || j.getState() == JobState.Failed)); + menu.addItem("Download result", job -> executeWSCallAsync("Downloading data", p -> job.downloadData(p)), job -> notNullValue(job, j -> EnumSet.of(JobState.Failed, JobState.Finished).contains(j.getState()) && !j.downloaded())); @@ -129,31 +136,21 @@ public class BenchmarkSPIMController implements FXFrame.Controller { }); } - private <V> void executeAsync(Executor executor, Callable<V> action, Consumer<V> postAction) { - executor.execute(() -> { - V result; - try { - result = action.call(); - postAction.accept(result); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - - }); - } - private void executeWSCallAsync(String title, P_JobAction action) { executeWSCallAsync(title, true, action); } private void executeWSCallAsync(String title, boolean update, P_JobAction action) { - executeAsync(executorServiceWS, (Callable<Void>) ()->{ + FXFrame.Controller.executeAsync(executorServiceWS, (Callable<Void>) () -> { ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(root, title), WindowConstants.DO_NOTHING_ON_CLOSE); action.doAction(dialog); dialog.done(); return null; - }, x-> {if(update) updateJobs(); }); + }, x -> { + if (update) + updateJobs(); + }); } private void updateJobs() { @@ -172,13 +169,11 @@ public class BenchmarkSPIMController implements FXFrame.Controller { throw new RuntimeException(e1); } executorServiceUI.execute(() -> { - Set<BenchmarkJob> old = new HashSet<BenchmarkJob>(jobs.getItems()); Map<BenchmarkJob, BenchmarkJob> actual; try { - actual = manager.getJobs().stream(). - collect(Collectors.toMap(job -> job, job -> job)); + actual = manager.getJobs().stream().collect(Collectors.toMap(job -> job, job -> job)); } catch (IOException e) { throw new RuntimeException(e); } @@ -199,7 +194,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller { }); }); }); - + } private void initTable() { @@ -210,11 +205,8 @@ public class BenchmarkSPIMController implements FXFrame.Controller { setCellValueFactory(4, j -> j.getEndTime().toString()); } - @SuppressWarnings("unchecked") private void setCellValueFactory(int index, Function<BenchmarkJob, String> mapper) { - ((TableColumn<BenchmarkJob, String>) jobs.getColumns().get(index)) - .setCellValueFactory(f -> new ObservableValueAdapter<BenchmarkJob, String>(f.getValue(), mapper)); - + FXFrame.Controller.setCellValueFactory(jobs, index, mapper); } private interface P_JobAction { diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/ObservableTaskRegistry.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/ObservableTaskRegistry.java new file mode 100644 index 00000000..71876913 --- /dev/null +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/ObservableTaskRegistry.java @@ -0,0 +1,30 @@ +package cz.it4i.fiji.haas_spim_benchmark.ui; + +import java.util.function.Consumer; + +import cz.it4i.fiji.haas.ui.ObservableValueRegistry; +import cz.it4i.fiji.haas_java_client.JobState; +import cz.it4i.fiji.haas_spim_benchmark.core.Task; +import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation; + +public class ObservableTaskRegistry extends ObservableValueRegistry<Task>{ + + public ObservableTaskRegistry( + Consumer<Task> removeConsumer) { + super(x->true, t->update(t), removeConsumer); + } + + private static boolean update(Task t) { + boolean result = true; + t.update(); + for(TaskComputation tc: t.getComputations()) { + JobState oldState = tc.getState(); + tc.update(); + result &= oldState == tc.getState(); + } + return result; + } + + + +} diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml new file mode 100644 index 00000000..f16482fd --- /dev/null +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.TableColumn?> +<?import javafx.scene.control.TableView?> +<?import javafx.scene.layout.BorderPane?> + +<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="912.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.it4i.fiji.haas_spim_benchmark.ui.SPIMPipelineProgressViewController"> + <center> + <TableView fx:id="jobs" prefHeight="400.0" prefWidth="675.0" BorderPane.alignment="CENTER"> + <columns> + <TableColumn prefWidth="101.0" text="Task name" /> + </columns> + </TableView> + </center> +</BorderPane> diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java new file mode 100644 index 00000000..90cb1147 --- /dev/null +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java @@ -0,0 +1,97 @@ +package cz.it4i.fiji.haas_spim_benchmark.ui; + +import java.awt.Window; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.function.Function; +import java.util.stream.Collectors; + +import cz.it4i.fiji.haas.ui.FXFrame; +import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob; +import cz.it4i.fiji.haas_spim_benchmark.core.Constants; +import cz.it4i.fiji.haas_spim_benchmark.core.Task; +import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; + +public class SPIMPipelineProgressViewController implements FXFrame.Controller { + + @FXML + private TableView<ObservableValue<Task>> tasks; + + private BenchmarkJob job; + private Timer timer; + private ObservableTaskRegistry registry; + + @Override + public void init(Window frame) { + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowClosed(WindowEvent e) { + super.windowClosed(e); + dispose(); + } + + }); + timer = new Timer(); + } + + public void setBenchmarkJob(BenchmarkJob job) { + this.job = job; + registry = new ObservableTaskRegistry(task -> tasks.getItems().remove(registry.remove(task))); + fillTable(); + } + + private void fillTable() { + List<Task> tasks = job.getTasks(); + if (tasks == null) { + timer.schedule(new TimerTask() { + @Override + public void run() { + fillTable(); + } + }, Constants.HAAS_UPDATE_TIMEOUT / 10); + } else { + List<TaskComputation> computations = tasks.stream().map(task -> task.getComputations()) + .collect(Collectors.<List<TaskComputation>>maxBy((a, b) -> a.size() - b.size())).get(); + int i = 0; + FXFrame.Controller.setCellValueFactory(this.tasks, i++, (Function<Task, String>) v -> v.getDescription()); + + for (TaskComputation tc : computations) { + this.tasks.getColumns().add(new TableColumn<>(tc.getTimepoint() + "")); + int index = i; + FXFrame.Controller.setCellValueFactory(this.tasks, i, (Function<Task, String>) v -> { + List<TaskComputation> items = v.getComputations(); + if (items.size() >= index) { + return ""; + } else { + return v.getComputations().get(index).getState().toString(); + } + }); + } + + this.tasks.getItems() + .addAll((tasks.stream().map(task -> registry.addIfAbsent(task)).collect(Collectors.toList()))); + timer.schedule(new TimerTask() { + @Override + public void run() { + updateTable(); + } + }, Constants.HAAS_UPDATE_TIMEOUT, Constants.HAAS_UPDATE_TIMEOUT); + + } + } + + private void updateTable() { + registry.update(); + } + + private void dispose() { + timer.cancel(); + } +} diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewWindow.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewWindow.java new file mode 100644 index 00000000..560a755c --- /dev/null +++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewWindow.java @@ -0,0 +1,19 @@ +package cz.it4i.fiji.haas_spim_benchmark.ui; + +import java.awt.Window; +import java.io.IOException; + +import cz.it4i.fiji.haas.ui.FXFrame; +import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob; + +public class SPIMPipelineProgressViewWindow extends FXFrame<SPIMPipelineProgressViewController> { + + private static final long serialVersionUID = 1L; + + public SPIMPipelineProgressViewWindow(Window applicationFrame,BenchmarkJob job) throws IOException { + super(applicationFrame, "/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml"); + init(controller->controller.setBenchmarkJob(job)); + } + + +} diff --git a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java new file mode 100644 index 00000000..2b4de27f --- /dev/null +++ b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java @@ -0,0 +1,14 @@ +package cz.it4i.fiji.haas; + +import java.io.IOException; + +import cz.it4i.fiji.haas_spim_benchmark.ui.SPIMPipelineProgressViewWindow; + +public class RunSPIMPipelineView { + + public static void main(String[] args) throws IOException { + new SPIMPipelineProgressViewWindow(null,null).setVisible(true); + + } + +} -- GitLab