diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaS.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaS.java index b38ce51f0f3d7ade20d20addd3a824fa0c0d1e59..2f70e73300d33ecf81aa9da2796638566fd8d438 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaS.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaS.java @@ -17,10 +17,8 @@ import org.scijava.ui.UIService; import org.scijava.widget.UIComponent; import cz.it4i.fiji.haas.JobManager.JobInfo; -import javafx.application.Platform; +import cz.it4i.fiji.haas.ui.ProgressDialog; import net.imagej.ImageJ; -import net.imagej.ui.swing.updater.ProgressDialog; -import net.imagej.updater.util.Progress; /** * @@ -52,28 +50,25 @@ public class CheckStatusOfHaaS implements Command { downloadAll(); } else { CheckStatusOfHaaSWindow window; - (window = new CheckStatusOfHaaSWindow(getFrame(),context)).setVisible(true); - - Platform.runLater(() -> { - Progress dialog = new ProgressDialog(getFrame()); - dialog.setTitle("Downloading info about jobs"); - Collection<JobInfo> jobs = jobManager.getJobs(); - int count = 0; - for(JobInfo ji: jobs) { - String item; - dialog.addItem(item = "job id:" + ji.getId()); - try { - ji.updateInfo(); - } catch (IOException e) { - log.error(e); - } - window.addJob(ji); - dialog.itemDone(item); - dialog.setCount(count, jobs.size()); - count++; + window = ModalDialogs.doModal(new CheckStatusOfHaaSWindow(getFrame(), context)); + ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(window)); + dialog.setTitle("Downloading info about jobs"); + Collection<JobInfo> jobs = jobManager.getJobs(); + int count = 0; + for (JobInfo ji : jobs) { + String item; + dialog.addItem(item = "job id:" + ji.getId()); + try { + ji.updateInfo(); + } catch (IOException e) { + log.error(e); } - dialog.done(); - }); + window.addJob(ji); + dialog.itemDone(item); + dialog.setCount(count, jobs.size()); + count++; + } + dialog.done(); } } catch (IOException e) { log.error(e); @@ -110,7 +105,7 @@ public class CheckStatusOfHaaS implements Command { final ImageJ ij = new ImageJ(); ij.launch(args); - // ij.command().run(CheckStatusOfHaaS.class, true); + ij.command().run(CheckStatusOfHaaS.class, true); } } diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaSWindow.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaSWindow.java index b206ea2bd6d6b658056263fa105abc06deefee23..6cccae8fe6a61e565a797651934093c4a8993abb 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaSWindow.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/CheckStatusOfHaaSWindow.java @@ -7,6 +7,7 @@ import org.scijava.plugin.Parameter; import cz.it4i.fiji.haas.JobManager.JobInfo; import cz.it4i.fiji.haas.ui.CheckStatusOfHaaSController; +import javafx.application.Platform; public class CheckStatusOfHaaSWindow extends FXFrame<CheckStatusOfHaaSController> { @@ -17,24 +18,27 @@ public class CheckStatusOfHaaSWindow extends FXFrame<CheckStatusOfHaaSController private CheckStatusOfHaaSController controller; - private Frame applicationFrame; public CheckStatusOfHaaSWindow(Frame applicationFrame, Context context) { super(applicationFrame,"/cz/it4i/fiji/haas/ui/CheckStatusOfHaaS.fxml"); this.context = context; init(this::initController); this.setResizable(false); this.setTitle("Manage status of HaaS jobs"); - this.applicationFrame = applicationFrame; } public void addJob(JobInfo job) { - controller.addJob(job); + Platform.runLater(new Runnable() { + @Override + public void run() { + controller.addJob(job); + } + }); } private void initController(CheckStatusOfHaaSController controller) { this.controller = controller; context.inject(controller); - controller.init(applicationFrame); + controller.init(this); } } diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/FXFrame.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/FXFrame.java index a1bac967f0c0ce3239701daa95de82cf77c71979..3c71c41c00579a5356b65601f66f0e2a39290d29 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/FXFrame.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/FXFrame.java @@ -36,9 +36,9 @@ public class FXFrame<C> extends JDialog { protected void init( Consumer<C> controlerInit) { this.controlerInit = controlerInit; this.fxPanel = new JFXPanel(); + Platform.setImplicitExit(false); this.add(this.fxPanel); - this.setVisible(true); - + // The call to runLater() avoid a mix between JavaFX thread and Swing thread. Platform.runLater(new Runnable() { @Override diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ModalDialogs.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ModalDialogs.java new file mode 100644 index 0000000000000000000000000000000000000000..f39f415d4b860d5d9ab566205cef2d7a9df05302 --- /dev/null +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ModalDialogs.java @@ -0,0 +1,21 @@ +package cz.it4i.fiji.haas; + +import javax.swing.WindowConstants; + +import cz.it4i.fiji.haas.ui.ProgressDialog; + +public class ModalDialogs { + public static ProgressDialog doModal(ProgressDialog dialog) { + dialog.setModal(true); + dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + new Thread(()->dialog.setVisible(true)).start(); + return dialog; + } + + public static CheckStatusOfHaaSWindow doModal(CheckStatusOfHaaSWindow window) { + window.setModal(true); + window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + new Thread(() -> window.setVisible(true)).start(); + return window; + } +} diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/RunWithHaaS.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/RunWithHaaS.java index 200b77e3b4a318bc3c07a2152c97cb1b5dbd59c8..0173de49e57911e8c3596d1fa70ce6243f798fa0 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/RunWithHaaS.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/RunWithHaaS.java @@ -1,5 +1,6 @@ package cz.it4i.fiji.haas; +import java.awt.Frame; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -13,9 +14,13 @@ import org.scijava.command.Command; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; +import org.scijava.ui.ApplicationFrame; +import org.scijava.ui.UIService; +import org.scijava.widget.UIComponent; +import cz.it4i.fiji.haas.ui.ProgressDialog; import net.imagej.ImageJ; -import net.imagej.ui.swing.updater.ProgressDialog; + /** * * @author koz01 @@ -24,46 +29,60 @@ import net.imagej.ui.swing.updater.ProgressDialog; @Plugin(type = Command.class, headless = true, menuPath = "Plugins>Run with HaaS") public class RunWithHaaS implements Command { + @Parameter + private UIService uiService; + @Parameter private LogService log; - @Parameter(label="Work directory",persist=true, style = "directory") + @Parameter(label = "Work directory", persist = true, style = "directory") private File workDirectory; - - @Parameter(label="Data directory",persist=true, style = "directory") + + @Parameter(label = "Data directory", persist = true, style = "directory") private File dataDirectory; - + @Parameter - private Context context; - + private Context context; + private JobManager jobManager; - + @Override public void run() { try { jobManager = new JobManager(getWorkingDirectoryPath(), context); - jobManager.startJob(getWorkingDirectoryPath(),getContent(dataDirectory), new ProgressDialog(null)); + jobManager.startJob(getWorkingDirectoryPath(), getContent(dataDirectory), + ModalDialogs.doModal(new ProgressDialog(getFrame()))); } catch (IOException e) { log.error(e); } } - private Path getWorkingDirectoryPath() { return Paths.get(workDirectory.toString()); } - private Collection<Path> getContent(File dataDirectory) throws IOException { return Files.list(Paths.get(dataDirectory.toString())).collect(Collectors.toList()); } + private Frame getFrame() { + ApplicationFrame af = uiService.getDefaultUI().getApplicationFrame(); + if (af instanceof Frame) { + return (Frame) af; + } else if (af instanceof UIComponent) { + Object component = ((UIComponent<?>) af).getComponent(); + if (component instanceof Frame) { + return (Frame) component; + } + } + return null; + } public static void main(final String... args) { // Launch ImageJ as usual. final ImageJ ij = new ImageJ(); ij.launch(args); - + ij.command().run(RunWithHaaS.class, true); } diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/CheckStatusOfHaaSController.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/CheckStatusOfHaaSController.java index fa9f59dd93680abae257270d8043ff99cb26f165..4a94de45e168f3ee2588fbc805eb98b39ac45edd 100644 --- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/CheckStatusOfHaaSController.java +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/CheckStatusOfHaaSController.java @@ -1,12 +1,13 @@ package cz.it4i.fiji.haas.ui; -import java.awt.Frame; +import java.awt.Window; import java.util.function.Function; import org.scijava.log.LogService; import org.scijava.plugin.Parameter; import cz.it4i.fiji.haas.JobManager.JobInfo; +import cz.it4i.fiji.haas.ModalDialogs; import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.event.EventHandler; @@ -16,7 +17,7 @@ import javafx.scene.control.MenuItem; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.input.ContextMenuEvent; -import net.imagej.ui.swing.updater.ProgressDialog; + public class CheckStatusOfHaaSController { @@ -26,7 +27,7 @@ public class CheckStatusOfHaaSController { @FXML private TableView<JobInfo> jobs; - private Frame root; + private Window root; public CheckStatusOfHaaSController() { @@ -36,14 +37,14 @@ public class CheckStatusOfHaaSController { jobs.getItems().add(job); } - public void init(Frame root) { + public void init(Window root) { initTable(); initMenu(); this.root = root; } private void downloadData(ActionEvent event) { - Platform.runLater(() -> jobs.getSelectionModel().getSelectedItem().downloadData(new ProgressDialog(root))); + Platform.runLater(() -> jobs.getSelectionModel().getSelectedItem().downloadData(ModalDialogs.doModal(new ProgressDialog(root)))); } private void initMenu() { diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java new file mode 100644 index 0000000000000000000000000000000000000000..bad0f6b0a35256279c7ee089cbf0d30535aa3add --- /dev/null +++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java @@ -0,0 +1,280 @@ +package cz.it4i.fiji.haas.ui; + + +import java.awt.Adjustable; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; + +import net.imagej.ui.swing.updater.SwingTools; +import net.imagej.updater.util.Progress; +import net.imagej.updater.util.UpdateCanceledException; + +/** +* TODO +* +* @author Johannes Schindelin +*/ +@SuppressWarnings("serial") +public class ProgressDialog extends JDialog implements Progress { + + JProgressBar progress; + JButton detailsToggle; + int toggleHeight = -1; + JScrollPane detailsScrollPane; + Details details; + Detail latestDetail; + String title; + boolean canceled; + protected long latestUpdate, itemLatestUpdate; + + public ProgressDialog(final Window owner) { + this(owner, null); + } + + public ProgressDialog(final Window owner, final String title) { + super(owner); + + final Container root = getContentPane(); + root.setLayout(new BoxLayout(root, BoxLayout.Y_AXIS)); + progress = new JProgressBar(); + progress.setStringPainted(true); + progress.setMinimum(0); + root.add(progress); + + final JPanel buttons = new JPanel(); + detailsToggle = new JButton("Show Details"); + detailsToggle.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent event) { + toggleDetails(); + } + }); + buttons.add(detailsToggle); + final JButton cancel = new JButton("Cancel"); + cancel.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(final ActionEvent e) { + canceled = true; + ProgressDialog.this.dispose(); + } + }); + buttons.add(cancel); + buttons.setMaximumSize(buttons.getMinimumSize()); + root.add(buttons); + + details = new Details(); + detailsScrollPane = + new JScrollPane(details, + ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); + detailsScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() { + + @Override + public void adjustmentValueChanged(AdjustmentEvent e) { + final int value = e.getValue(); + final Adjustable adjustable = e.getAdjustable(); + final int maximum = adjustable.getMaximum(); + if (value != maximum) + adjustable.setValue(maximum); + } + }); + detailsScrollPane.setVisible(false); + root.add(detailsScrollPane); + + if (title != null) setTitle(title); + pack(); + + if (owner != null) { + final Dimension o = owner.getSize(); + final Dimension size = getSize(); + if (size.width < o.width / 2) { + size.width = o.width / 2; + setSize(size); + } + setLocation(owner.getX() + (o.width - size.width) / 2, owner.getY() + + (o.height - size.height) / 2); + } + + final KeyAdapter keyAdapter = new KeyAdapter() { + + @Override + public void keyReleased(final KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) cancel(); + } + }; + root.addKeyListener(keyAdapter); + detailsToggle.addKeyListener(keyAdapter); + cancel.addKeyListener(keyAdapter); + + setLocationRelativeTo(null); + if (title != null) setVisible(true); + } + + public void cancel() { + canceled = true; + } + + protected void checkIfCanceled() { + if (canceled) throw new UpdateCanceledException(); + } + + @Override + public void setTitle(final String title) { + this.title = title; + setTitle(); + setVisible(true); + } + + protected void setTitle() { + checkIfCanceled(); + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + if (detailsScrollPane.isVisible() || latestDetail == null) progress + .setString(title); + else progress.setString(title + ": " + latestDetail.getString()); + } + }); + repaint(); + } + + @Override + public void setCount(final int count, final int total) { + checkIfCanceled(); + if (updatesTooFast()) return; + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + progress.setMaximum(total); + progress.setValue(count); + } + }); + repaint(); + } + + @Override + public void addItem(final Object item) { + checkIfCanceled(); + details.addDetail(item.toString()); + if (itemUpdatesTooFast() && !detailsScrollPane.isVisible()) return; + setTitle(); + validate(); + repaint(); + } + + @Override + public void setItemCount(final int count, final int total) { + checkIfCanceled(); + if (itemUpdatesTooFast()) return; + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + latestDetail.setMaximum(total); + latestDetail.setValue(count); + repaint(); + } + }); + } + + @Override + public void itemDone(final Object item) { + checkIfCanceled(); + if (itemUpdatesTooFast() && !detailsScrollPane.isVisible()) return; + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + latestDetail.setValue(latestDetail.getMaximum()); + } + }); + } + + @Override + public void done() { + if (latestDetail != null) latestDetail.setValue(latestDetail.getMaximum()); + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + progress.setValue(progress.getMaximum()); + dispose(); + } + }); + } + + public void toggleDetails() { + SwingTools.invokeOnEDT(new Runnable() { + @Override + public void run() { + final boolean show = !detailsScrollPane.isVisible(); + detailsScrollPane.setVisible(show); + detailsScrollPane.invalidate(); + detailsToggle.setText(show ? "Hide Details" : "Show Details"); + setTitle(); + + final Dimension dimension = getSize(); + if (toggleHeight == -1) toggleHeight = dimension.height + 100; + setSize(new Dimension(dimension.width, toggleHeight)); + toggleHeight = dimension.height; + } + }); + } + + private class Details extends JPanel { + + Details() { + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + } + + public void addDetail(final String title) { + addDetail(new Detail(title)); + } + + public void addDetail(final Detail detail) { + add(detail); + latestDetail = detail; + } + } + + private class Detail extends JProgressBar { + + Detail(final String text) { + setStringPainted(true); + setString(text); + } + } + + protected boolean updatesTooFast() { + if (System.currentTimeMillis() - latestUpdate < 50) return true; + latestUpdate = System.currentTimeMillis(); + return false; + } + + protected boolean itemUpdatesTooFast() { + if (System.currentTimeMillis() - itemLatestUpdate < 50) return true; + itemLatestUpdate = System.currentTimeMillis(); + return false; + } + + public static void main(final String[] args) { + final ProgressDialog dialog = new ProgressDialog(null, "Hello"); + dialog.addItem("Bello"); + dialog.setVisible(true); + } +} + diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java index 70e1814b3d99d9abc06fd0b80a1970f576016981..e96e046d00a9563e097e4bea2c2674d3c8176a47 100644 --- a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java +++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java @@ -188,9 +188,7 @@ public class HaaSClient { final SubmittedJobInfoExt info = getJobManagement().getCurrentInfoForJob(jobId, getSessionID()); final Collection<Long> tasksId = Arrays.asList(info.getTasks()).stream().map(ti -> ti.getId()) .collect(Collectors.toList()); - return new JobInfo() { - @Override public Collection<Long> getTasks() { return tasksId; @@ -421,6 +419,5 @@ public class HaaSClient { public void done() { notifier.done(); } - } } diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/TransferFileProgressForHaaSClient.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/TransferFileProgressForHaaSClient.java index a103335176805adc99938b91bc92f686ccbf7dc0..361e82710da0a615e6fd8117223f99c2d52ce623 100644 --- a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/TransferFileProgressForHaaSClient.java +++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/TransferFileProgressForHaaSClient.java @@ -36,7 +36,7 @@ class TransferFileProgressForHaaSClient implements TransferFileProgress { } - private int[] normalizaSizes(long part, long total) { + private static int[] normalizaSizes(long part, long total) { int[] result = new int[2]; if(total > Integer.MAX_VALUE) { part = part>>10;