diff --git a/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java b/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java index 022da38..b2695e0 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/N5ImageHandler.java @@ -10,14 +10,13 @@ import org.scijava.log.slf4j.SLF4JLogService; import org.scijava.plugin.Parameter; import org.scijava.plugin.Plugin; +import org.vcell.N5.UI.MainPanel; import org.vcell.N5.UI.N5ExportTable; +import org.vcell.N5.retrieving.LoadingFactory; +import org.vcell.N5.retrieving.SimResultsLoader; import java.io.*; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; -import java.util.Stack; /* @@ -32,17 +31,18 @@ public class N5ImageHandler implements Command { public static final String formatName = "N5"; @Parameter public static LogService logService; - public static N5ExportTable exportTable; + public static MainPanel exportTable; public static String exportedMetaDataPath = System.getProperty("user.home") + "/.vcell/exportMetaData.json"; private static ExportDataRepresentation.FormatExportDataRepresentation exampleJSONData; + public static LoadingFactory loadingFactory; @Override public void run() { - exportTable = new N5ExportTable(); initializeLogService(); + loadingFactory = new LoadingFactory(); + exportTable = new MainPanel(); setExampleJSONData(); // N5ImageHandler.logService.setLevel(LogService.DEBUG); - exportTable.displayExportTable(); Thread thread = new Thread(() -> { // For some reason getting a standard client takes three seconds. // So create one upon initialization, while the user is focused on the GUI diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java new file mode 100644 index 0000000..9eb0579 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/ControlButtonsPanel.java @@ -0,0 +1,203 @@ +package org.vcell.N5.UI; + +import org.vcell.N5.N5ImageHandler; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.time.LocalDateTime; +import java.util.Enumeration; + +public class ControlButtonsPanel extends JPanel implements ActionListener { + + private static JButton openOrCancel; +// private final JButton openLocal = new JButton("Open N5 Local"); + private final JButton copyLink; + private final JButton useN5Link; + private final JButton questionMark; + private final JButton openInMemory; + private final JCheckBox includeExampleExports; + private final JCheckBox todayInterval; + private final JCheckBox monthInterval; + private final JCheckBox yearlyInterval; + private final JCheckBox anyInterval; + private final JPanel timeFilter; + + private N5ExportTable n5ExportTable; + private RemoteFileSelection remoteFileSelection; + + public ControlButtonsPanel(){ + openOrCancel = new JButton("Open"); + copyLink = new JButton("Copy Link"); + useN5Link = new JButton("Use N5 Link"); + questionMark = new JButton("?"); + questionMark.setPreferredSize(new Dimension(20, 20)); + openInMemory = new JButton("Open In Memory"); + openInMemory.setSelected(false); + includeExampleExports = new JCheckBox("Show Example Exports"); + includeExampleExports.setSelected(!N5ImageHandler.exportedDataExists()); + + GridBagConstraints gridBagConstraints = new GridBagConstraints(); + + JPanel topRow = new JPanel(new GridBagLayout()); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + topRow.add(openOrCancel, gridBagConstraints); + gridBagConstraints.gridwidth = 1; + + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 0; + topRow.add(openInMemory, gridBagConstraints); + gridBagConstraints.gridx = 2; + + JPanel bottomRow = new JPanel(new GridBagLayout()); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + bottomRow.add(copyLink, gridBagConstraints); + gridBagConstraints.gridx = 1; + bottomRow.add(useN5Link, gridBagConstraints); + bottomRow.add(questionMark); + + + JPanel userButtonsPanel = new JPanel(new GridBagLayout()); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 0; + userButtonsPanel.add(topRow, gridBagConstraints); + gridBagConstraints.gridy = 1; + userButtonsPanel.add(bottomRow, gridBagConstraints); + +// buttonsPanel.add(questionMark); + + + todayInterval = new JCheckBox("Past 24 Hours"); + monthInterval = new JCheckBox("Past Month"); + yearlyInterval = new JCheckBox("Past Year"); + anyInterval = new JCheckBox("Any Time"); + anyInterval.setSelected(true); + + ButtonGroup buttonGroup = new ButtonGroup(); + buttonGroup.add(todayInterval); + buttonGroup.add(monthInterval); + buttonGroup.add(yearlyInterval); + buttonGroup.add(anyInterval); + + JPanel filters = new JPanel(); + filters.setLayout(new BorderLayout()); + timeFilter = new JPanel(new GridBagLayout()); + timeFilter.add(anyInterval); + timeFilter.add(todayInterval); + timeFilter.add(monthInterval); + timeFilter.add(yearlyInterval); +// timeFilter.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Time ")); + filters.add(timeFilter, BorderLayout.NORTH); + filters.add(includeExampleExports, BorderLayout.SOUTH); + Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); + filters.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Filters ")); + + + int paneWidth = 800; + this.setPreferredSize(new Dimension(paneWidth, 100)); + this.setLayout(new BorderLayout()); +// topBar.add(openLocal); + this.add(userButtonsPanel, BorderLayout.EAST); + this.add(filters, BorderLayout.WEST); + this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " User Options ")); + + + openOrCancel.addActionListener(this); + copyLink.addActionListener(this); + questionMark.addActionListener(this); + useN5Link.addActionListener(this); + includeExampleExports.addActionListener(this); +// openLocal.addActionListener(this); + openInMemory.addActionListener(this); + + Enumeration b = buttonGroup.getElements(); + while (b.hasMoreElements()){ + b.nextElement().addActionListener(this); + } + + openOrCancel.setEnabled(false); + copyLink.setEnabled(false); + openInMemory.setEnabled(false); + } + + public void initialize(N5ExportTable n5ExportTable, RemoteFileSelection remoteFileSelection){ + this.n5ExportTable = n5ExportTable; + this.remoteFileSelection = remoteFileSelection; + } + + @Override + public void actionPerformed(ActionEvent e) { + if(e.getSource().equals(openOrCancel) || e.getSource().equals(openInMemory)){ + if (openOrCancel.getText().equals("Cancel")){ + n5ExportTable.removeFromLoadingRows(); + } else { + n5ExportTable.openSelectedRows(e.getSource().equals(openInMemory)); + } + } else if (e.getSource().equals(copyLink)) { + n5ExportTable.copySelectedRowLink(); + } else if (e.getSource().equals(questionMark)) { + new HelpExplanation().displayHelpMenu(); + } else if (e.getSource().equals(useN5Link)) { + remoteFileSelection.setVisible(true); + } else if (e.getSource().equals(includeExampleExports)){ + if(includeExampleExports.isSelected()){ + n5ExportTable.updateExampleExportsToTable(); + return; + } + n5ExportTable.updateTableData(); + } else if (e.getSource().equals(anyInterval) || e.getSource().equals(todayInterval) + || e.getSource().equals(monthInterval) || e.getSource().equals(yearlyInterval)) { + if(includeExampleExports.isSelected()){ + n5ExportTable.updateExampleExportsToTable(); + return; + } + n5ExportTable.updateTableData(); + } + } + + public LocalDateTime oldestTimeAllowed(){ + LocalDateTime pastTime = LocalDateTime.now(); + if (todayInterval.isSelected()){ + pastTime = pastTime.minusDays(1); + } else if (monthInterval.isSelected()) { + pastTime = pastTime.minusMonths(1); + } else if (yearlyInterval.isSelected()) { + pastTime = pastTime.minusYears(1); + } else { + pastTime = pastTime.minusYears(10); //Max date back is 10 years + } + return pastTime; + } + + public void allowCancel(boolean allow){ + openOrCancel.setEnabled(true); + copyLink.setEnabled(true); + openInMemory.setEnabled(!allow); + useN5Link.setEnabled(true); + remoteFileSelection.submitS3Info.setEnabled(true); + if (allow){ + openOrCancel.setText("Cancel"); + } else { + openOrCancel.setText("Open"); + } + } + + public void enableRowContextDependentButtons(boolean enable){ + openOrCancel.setEnabled(enable); + copyLink.setEnabled(enable); + openInMemory.setEnabled(enable); + } + + public void enableCriticalButtons(boolean enable){ + useN5Link.setEnabled(enable); + openOrCancel.setEnabled(enable); + copyLink.setEnabled(enable); + remoteFileSelection.submitS3Info.setEnabled(enable); + openInMemory.setEnabled(enable); + } +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/ExportDetailsPanel.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/ExportDetailsPanel.java new file mode 100644 index 0000000..9e9da45 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/ExportDetailsPanel.java @@ -0,0 +1,117 @@ +package org.vcell.N5.UI; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; +import javax.swing.table.AbstractTableModel; +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class ExportDetailsPanel extends JSplitPane { + private final JTextPane variableTextPanel; + private final Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); + private final ParameterTableModel parameterTableModel; + private final JTable parameterTable; + + + public ExportDetailsPanel(){ + super(JSplitPane.HORIZONTAL_SPLIT); + variableTextPanel = new JTextPane(); + parameterTableModel = new ParameterTableModel(); + parameterTable = new JTable(parameterTableModel); + JScrollPane parameterTableScrollPane = new JScrollPane(parameterTable); + int paneWidth = 800; + parameterTableScrollPane.setPreferredSize(new Dimension(paneWidth / 2, 80)); + parameterTableScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Parameter Values ")); +// jTextPane.setSize(800, 200); + variableTextPanel.setEditable(false); + JScrollPane jtextScrollPane = new JScrollPane(variableTextPanel); + jtextScrollPane.setPreferredSize(new Dimension(paneWidth / 2, 80)); + jtextScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Variables ")); + + this.add(jtextScrollPane); + this.add(parameterTableScrollPane); +// exportDetails = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jtextScrollPane, parameterTableScrollPane); + this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Export Details ")); + this.setResizeWeight(0.5); + this.setContinuousLayout(true); + + MainPanel.setEnableParentAndChild(this, false); +// return exportDetails; + } + + public void resetExportDetails(){ + parameterTableModel.resetTableData(); + variableTextPanel.setText(""); + MainPanel.setEnableParentAndChild(this, false); + } + + public void addExportDetailEntries(String variableText, ArrayList parameters){ + variableTextPanel.setText(variableText); + for(String parameterValues : parameters){ + String[] tokens = parameterValues.split(":"); + parameterTableModel.addRowData(tokens[0], tokens[1], tokens[2]); + } + variableTextPanel.updateUI(); + parameterTable.updateUI(); + } + + + static class ParameterTableModel extends AbstractTableModel { + + private final static String parameterHeader = "Parameter"; + private final static String defaultValueHeader = "Default Value"; + private final static String newValueHeader = "New Value"; + + + private List> tableData = new ArrayList<>(); + private final ArrayList headers = new ArrayList(){{ + add(parameterHeader); + add(defaultValueHeader); + add(newValueHeader); + }}; + @Override + public String getColumnName(int column) { + return headers.get(column); + } + + @Override + public int getRowCount() { + return tableData.size(); + } + + @Override + public int getColumnCount() { + return headers.size(); + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + HashMap rowData = tableData.get(rowIndex); + if(columnIndex == headers.indexOf(parameterHeader)){ + return rowData.get(parameterHeader); + } else if (columnIndex == headers.indexOf(defaultValueHeader)) { + return rowData.get(defaultValueHeader); + } else if (columnIndex == headers.indexOf(newValueHeader)) { + return rowData.get(newValueHeader); + } + return null; + } + + public void addRowData(String parameterName, String defaultValue, String newValue){ + HashMap data = new HashMap(){{ + put(parameterHeader, parameterName); + put(defaultValueHeader, defaultValue); + put(newValueHeader, newValue); + }}; + tableData.add(data); + } + + public void resetTableData(){ + tableData = new ArrayList<>(); + } + + } +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java new file mode 100644 index 0000000..a49f5b7 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/MainPanel.java @@ -0,0 +1,66 @@ +package org.vcell.N5.UI; + +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableColumn; +import java.awt.*; +import java.util.Enumeration; + +public class MainPanel { + private static JDialog exportTableDialog; + private final int paneWidth = 800; + + public final static ControlButtonsPanel controlButtonsPanel = new ControlButtonsPanel(); + public final N5ExportTable n5ExportTable = new N5ExportTable(); + public final ExportDetailsPanel exportDetailsPanel = new ExportDetailsPanel(); + public final RemoteFileSelection remoteFileSelection = new RemoteFileSelection(); + + + public MainPanel(){ + JPanel parentPanel = new JPanel(); + + + n5ExportTable.initialize(controlButtonsPanel, exportDetailsPanel); + controlButtonsPanel.initialize(n5ExportTable, remoteFileSelection); + + parentPanel.setLayout(new BorderLayout()); + parentPanel.add(controlButtonsPanel, BorderLayout.NORTH); + JSplitPane jSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, n5ExportTable, exportDetailsPanel); + jSplitPane.setContinuousLayout(true); + parentPanel.add(jSplitPane, BorderLayout.CENTER); + + parentPanel.setPreferredSize(new Dimension(paneWidth, 650)); + JOptionPane pane = new JOptionPane(parentPanel, JOptionPane.PLAIN_MESSAGE, 0, null, new Object[]{"Close"}); + exportTableDialog = pane.createDialog("VCell Exports"); + exportTableDialog.setModal(false); + exportTableDialog.setResizable(true); + exportTableDialog.setVisible(true); + } + + public static void changeCursor(Cursor cursor){ + exportTableDialog.setCursor(cursor); + } + + public static void setEnableParentAndChild(Container container, boolean enable){ + container.setEnabled(enable); + for (Component component : container.getComponents()){ + if (component instanceof Container){ + setEnableParentAndChild((Container) component, enable); + } + component.setEnabled(enable); + if(component instanceof JTable){ + Enumeration columns = ((JTable) component).getColumnModel().getColumns(); + while (columns.hasMoreElements()){ + columns.nextElement().setHeaderRenderer(new DefaultTableCellRenderer(){ + @Override + public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { + Component c = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column); + c.setForeground(enable ? Color.BLACK : Color.GRAY); + return c; + } + }); + } + } + } + } +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java index 08d8dbf..f9de4e0 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/N5ExportTable.java @@ -1,15 +1,10 @@ package org.vcell.N5.UI; -import ij.ImagePlus; -import net.imglib2.cache.img.CachedCellImg; -import net.imglib2.img.display.imagej.ImageJFunctions; -import net.imglib2.type.numeric.real.DoubleType; -import org.janelia.saalfeldlab.n5.N5FSReader; import org.scijava.log.Logger; import org.vcell.N5.ExportDataRepresentation; import org.vcell.N5.N5ImageHandler; -import org.vcell.N5.SimCacheLoader; -import org.vcell.N5.SimResultsLoader; +import org.vcell.N5.retrieving.SimLoadingListener; +import org.vcell.N5.retrieving.SimResultsLoader; import javax.swing.*; import javax.swing.border.Border; @@ -18,103 +13,126 @@ import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableColumn; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; import java.io.FileNotFoundException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.List; import java.util.*; import java.util.concurrent.TimeUnit; -public class N5ExportTable implements ActionListener, ListSelectionListener { - public static JDialog exportTableDialog; +public class N5ExportTable extends JScrollPane implements ListSelectionListener, SimLoadingListener { private N5ExportTableModel n5ExportTableModel; - private ParameterTableModel parameterTableModel; - private JTable parameterTable; private JTable exportListTable; - private JScrollPane tableScrollPane; - private JSplitPane exportDetails; - - private static JButton open; - private static final JButton openLocal = new JButton("Open N5 Local"); - private static JButton copyLink; - private static JButton refreshButton; - private static JButton useN5Link; - private static JButton questionMark; - public static JButton openInMemory; - public static JCheckBox includeExampleExports; - private JCheckBox todayInterval; - private JCheckBox monthInterval; - private JCheckBox yearlyInterval; - private JCheckBox anyInterval; - private JPanel timeFilter; - private JTextPane variableTextPanel; + private final Border lowerEtchedBorder = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED); private final Border exampleBorder = BorderFactory.createTitledBorder(lowerEtchedBorder, "Example Exports"); - private static RemoteFileSelection remoteFileSelection; - private final int paneWidth = 800; + private final Map loadingRowsJobID = new HashMap<>(); + + private ControlButtonsPanel controlPanel; + private ExportDetailsPanel exportDetailsPanel; + private final Logger logger = N5ImageHandler.getLogger(N5ExportTable.class); - public N5ExportTable(){ - remoteFileSelection = new RemoteFileSelection(); + public N5ExportTable(){} + + public void initialize(ControlButtonsPanel controlButtonsPanel, ExportDetailsPanel exportDetailsPanel){ + this.controlPanel = controlButtonsPanel; + this.exportDetailsPanel = exportDetailsPanel; + N5ImageHandler.loadingFactory.addSimLoadingListener(this); + n5ExportTableModel = new N5ExportTableModel(); + exportListTable = new JTable(n5ExportTableModel); + this.setViewportView(exportListTable); + + + DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer(){ + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + int actualRow = loadingRowsJobID.containsKey(row) ? findLoadingRow(row, row) : -1; + if (actualRow != -1){ + cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, actualRow, column); + cell.setForeground(Color.decode("#228B22")); + } else { + cell.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground()); + } + return cell; + } + }; + + int columns = n5ExportTableModel.getColumnCount(); + for (int i = 0; i < columns; i++){ + exportListTable.getColumnModel().getColumn(i).setCellRenderer(cellRenderer); + } + + this.setPreferredSize(new Dimension(500, 400)); + this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Export Table")); + exportListTable.getSelectionModel().addListSelectionListener(this); + + if(!N5ImageHandler.exportedDataExists()){ + updateExampleExportsToTable(); + } + else{ + updateTableData(); + } + automaticRefresh(); } - private LocalDateTime oldestTimeAllowed(){ - LocalDateTime pastTime = LocalDateTime.now(); - if (todayInterval.isSelected()){ - pastTime = pastTime.minusDays(1); - } else if (monthInterval.isSelected()) { - pastTime = pastTime.minusMonths(1); - } else if (yearlyInterval.isSelected()) { - pastTime = pastTime.minusYears(1); + void updateTableData(){ + // when initializing it is null + if (controlPanel == null){ + updateTableData(LocalDateTime.now().minusYears(10)); } else { - pastTime = pastTime.minusYears(10); //Max date back is 10 years + updateTableData(controlPanel.oldestTimeAllowed()); } - return pastTime; } - public void initalizeTableData(){ + void updateTableData(LocalDateTime oldestTimeAllowed){ n5ExportTableModel.resetData(); - tableScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Personal Exports")); + this.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Personal Exports")); try { ExportDataRepresentation.FormatExportDataRepresentation formatExportData = N5ImageHandler.getJsonData(); if (formatExportData != null){ Stack jobStack = formatExportData.formatJobIDs; while (!jobStack.isEmpty()){ String jobID = jobStack.pop(); - if (!n5ExportTableModel.appendRowData(formatExportData.simulationDataMap.get(jobID), oldestTimeAllowed())){ + if (!n5ExportTableModel.appendRowData(formatExportData.simulationDataMap.get(jobID), oldestTimeAllowed)){ break; } } } n5ExportTableModel.fireTableDataChanged(); - tableScrollPane.updateUI(); + this.updateUI(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } } - private void updateExampleExportsToTable(){ + void updateExampleExportsToTable(){ + // when initializing it is null + if (controlPanel == null){ + updateExampleExportsToTable(LocalDateTime.now().minusYears(10)); + } else { + updateExampleExportsToTable(controlPanel.oldestTimeAllowed()); + } + } + + void updateExampleExportsToTable(LocalDateTime oldestTimeAllowed){ n5ExportTableModel.resetData(); - tableScrollPane.setBorder(exampleBorder); + this.setBorder(exampleBorder); try{ ExportDataRepresentation.FormatExportDataRepresentation exampleFormatExportData = N5ImageHandler.getExampleJSONData(); Stack exampleJobStack = (Stack) exampleFormatExportData.formatJobIDs.clone(); while (!exampleJobStack.isEmpty()){ String jobID = exampleJobStack.pop(); - if (!n5ExportTableModel.appendRowData(exampleFormatExportData.simulationDataMap.get(jobID), oldestTimeAllowed())){ + if (!n5ExportTableModel.appendRowData(exampleFormatExportData.simulationDataMap.get(jobID), oldestTimeAllowed)){ break; } } n5ExportTableModel.fireTableDataChanged(); - tableScrollPane.updateUI(); + this.updateUI(); } catch (FileNotFoundException e){ throw new RuntimeException("Can't open example N5 export table.", e); @@ -126,7 +144,7 @@ private void automaticRefresh(){ try { while(true){ ExportDataRepresentation.FormatExportDataRepresentation formatExportData = N5ImageHandler.getJsonData(); - if (formatExportData != null && !tableScrollPane.getBorder().equals(exampleBorder)){ + if (formatExportData != null && !this.getBorder().equals(exampleBorder)){ ExportDataRepresentation.SimulationExportDataRepresentation mostRecentTableEntry = !n5ExportTableModel.tableData.isEmpty() ? n5ExportTableModel.tableData.getFirst() : null; Stack jobStack = formatExportData.formatJobIDs; boolean isUpdated = false; @@ -136,11 +154,12 @@ private void automaticRefresh(){ || !formatExportData.simulationDataMap.containsKey(mostRecentTableEntry.jobID))){ break; } - isUpdated = n5ExportTableModel.prependRowData(formatExportData.simulationDataMap.get(currentJob), oldestTimeAllowed()); + isUpdated = n5ExportTableModel.prependRowData(formatExportData.simulationDataMap.get(currentJob), controlPanel.oldestTimeAllowed()); } if(isUpdated){ n5ExportTableModel.fireTableDataChanged(); - tableScrollPane.updateUI(); + this.updateUI(); + exportListTable.repaint(); } } Thread.sleep(TimeUnit.SECONDS.toMillis(2)); @@ -154,336 +173,76 @@ private void automaticRefresh(){ refreshTableThread.start(); } - - private void initialize(){ - JPanel parentPanel = new JPanel(); - - parentPanel.setLayout(new BorderLayout()); - parentPanel.add(topPanel(), BorderLayout.NORTH); - JSplitPane jSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,tablePanel(), exportDetailsPanel()); - jSplitPane.setContinuousLayout(true); - parentPanel.add(jSplitPane, BorderLayout.CENTER); - - parentPanel.setPreferredSize(new Dimension(paneWidth, 650)); - JOptionPane pane = new JOptionPane(parentPanel, JOptionPane.PLAIN_MESSAGE, 0, null, new Object[]{"Close"}); - exportTableDialog = pane.createDialog("VCell Exports"); - exportTableDialog.setModal(false); - exportTableDialog.setResizable(true); - exportTableDialog.setVisible(true); - if(!N5ImageHandler.exportedDataExists()){ - updateExampleExportsToTable(); - } - else{ - initalizeTableData(); - } - automaticRefresh(); - } - - - public void displayExportTable() { - if (exportTableDialog == null) { - initialize(); - } else { - exportTableDialog.setVisible(true); + public void openSelectedRows(boolean inMemory){ + ArrayList filesToOpen = new ArrayList<>(); + for(int row: exportListTable.getSelectedRows()){ + String uri = n5ExportTableModel.getRowData(row).uri; + ExportDataRepresentation.SimulationExportDataRepresentation rowData = n5ExportTableModel.getRowData(row); + SimResultsLoader simResultsLoader = new SimResultsLoader(uri, rowData.savedFileName, row, rowData.jobID); + filesToOpen.add(simResultsLoader); } + N5ImageHandler.loadingFactory.openN5FileDataset(filesToOpen, inMemory); } - private JSplitPane exportDetailsPanel(){ - variableTextPanel = new JTextPane(); - parameterTableModel = new ParameterTableModel(); - parameterTable = new JTable(parameterTableModel); - JScrollPane parameterTableScrollPane = new JScrollPane(parameterTable); - parameterTableScrollPane.setPreferredSize(new Dimension(paneWidth / 2, 80)); - parameterTableScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Parameter Values ")); -// jTextPane.setSize(800, 200); - variableTextPanel.setEditable(false); - JScrollPane jtextScrollPane = new JScrollPane(variableTextPanel); - jtextScrollPane.setPreferredSize(new Dimension(paneWidth / 2, 80)); - jtextScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Variables ")); - - exportDetails = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jtextScrollPane, parameterTableScrollPane); - exportDetails.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Export Details ")); - exportDetails.setResizeWeight(0.5); - exportDetails.setContinuousLayout(true); - - setEnableParentAndChild(exportDetails, false); - return exportDetails; - } - - private JScrollPane tablePanel(){ - n5ExportTableModel = new N5ExportTableModel(); - exportListTable = new JTable(n5ExportTableModel); - tableScrollPane = new JScrollPane(exportListTable); - - - tableScrollPane.setPreferredSize(new Dimension(500, 400)); - tableScrollPane.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, "Export Table")); - exportListTable.getSelectionModel().addListSelectionListener(this); - - return tableScrollPane; + public void copySelectedRowLink(){ + ExportDataRepresentation.SimulationExportDataRepresentation selectedRow = n5ExportTableModel.getRowData(exportListTable.getSelectedRow()); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(new StringSelection(selectedRow.uri), null); } - private JPanel topPanel(){ - refreshButton = new JButton("Refresh"); - open = new JButton("Open"); - copyLink = new JButton("Copy Link"); - useN5Link = new JButton("Use N5 Link"); - questionMark = new JButton("?"); - questionMark.setPreferredSize(new Dimension(20, 20)); - openInMemory = new JButton("Open In Memory"); - openInMemory.setSelected(false); - includeExampleExports = new JCheckBox("Show Example Exports"); - includeExampleExports.setSelected(!N5ImageHandler.exportedDataExists()); - - GridBagConstraints gridBagConstraints = new GridBagConstraints(); - - JPanel topRow = new JPanel(new GridBagLayout()); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - topRow.add(open, gridBagConstraints); - gridBagConstraints.gridwidth = 1; - - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 0; - topRow.add(openInMemory, gridBagConstraints); - gridBagConstraints.gridx = 2; - - JPanel bottomRow = new JPanel(new GridBagLayout()); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - bottomRow.add(copyLink, gridBagConstraints); - gridBagConstraints.gridx = 1; - bottomRow.add(useN5Link, gridBagConstraints); - bottomRow.add(questionMark); - - - JPanel userButtonsPanel = new JPanel(new GridBagLayout()); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 0; - userButtonsPanel.add(topRow, gridBagConstraints); - gridBagConstraints.gridy = 1; - userButtonsPanel.add(bottomRow, gridBagConstraints); - -// buttonsPanel.add(questionMark); - - - todayInterval = new JCheckBox("Past 24 Hours"); - monthInterval = new JCheckBox("Past Month"); - yearlyInterval = new JCheckBox("Past Year"); - anyInterval = new JCheckBox("Any Time"); - anyInterval.setSelected(true); - - ButtonGroup buttonGroup = new ButtonGroup(); - buttonGroup.add(todayInterval); - buttonGroup.add(monthInterval); - buttonGroup.add(yearlyInterval); - buttonGroup.add(anyInterval); - - JPanel filters = new JPanel(); - filters.setLayout(new BorderLayout()); - timeFilter = new JPanel(new GridBagLayout()); - timeFilter.add(anyInterval); - timeFilter.add(todayInterval); - timeFilter.add(monthInterval); - timeFilter.add(yearlyInterval); -// timeFilter.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Time ")); - filters.add(timeFilter, BorderLayout.NORTH); - filters.add(includeExampleExports, BorderLayout.SOUTH); - filters.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " Filters ")); - - - JPanel topBar = new JPanel(); - topBar.setPreferredSize(new Dimension(paneWidth, 100)); - topBar.setLayout(new BorderLayout()); -// topBar.add(openLocal); - topBar.add(userButtonsPanel, BorderLayout.EAST); - topBar.add(filters, BorderLayout.WEST); - topBar.setBorder(BorderFactory.createTitledBorder(lowerEtchedBorder, " User Options ")); - - - refreshButton.addActionListener(this); - open.addActionListener(this); - copyLink.addActionListener(this); - questionMark.addActionListener(this); - useN5Link.addActionListener(this); - includeExampleExports.addActionListener(this); - openLocal.addActionListener(this); - openInMemory.addActionListener(this); - - Enumeration b = buttonGroup.getElements(); - while (b.hasMoreElements()){ - b.nextElement().addActionListener(this); + // The table may have changed by refreshing it, so if past idea of affected row no longer align correct it + private int findLoadingRow(int currentRow, int initialRow){ + String expectedJobID = loadingRowsJobID.get(initialRow); + if (currentRow < 0 || currentRow == n5ExportTableModel.getRowCount()){ + return -1; } - - open.setEnabled(false); - copyLink.setEnabled(false); - openInMemory.setEnabled(false); - - return topBar; - } - - public static void enableCriticalButtons(boolean enable){ - useN5Link.setEnabled(enable); - open.setEnabled(enable); - refreshButton.setEnabled(enable); - copyLink.setEnabled(enable); - remoteFileSelection.submitS3Info.setEnabled(enable); - openInMemory.setEnabled(enable); - } - - public static void setEnableParentAndChild(Container container, boolean enable){ - container.setEnabled(enable); - for (Component component : container.getComponents()){ - if (component instanceof Container){ - setEnableParentAndChild((Container) component, enable); + else if (n5ExportTableModel.getRowData(currentRow).jobID.equals(expectedJobID) && + currentRow < n5ExportTableModel.getRowCount()){ + if (currentRow != initialRow){ + loadingRowsJobID.put(currentRow, expectedJobID); + loadingRowsJobID.remove(initialRow); } - component.setEnabled(enable); - if(component instanceof JTable){ - Enumeration columns = ((JTable) component).getColumnModel().getColumns(); - while (columns.hasMoreElements()){ - columns.nextElement().setHeaderRenderer(new DefaultTableCellRenderer(){ - @Override - public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) { - Component c = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column); - c.setForeground(enable ? Color.BLACK : Color.GRAY); - return c; - } - }); - } - } - } - } - - @Override - public void actionPerformed(ActionEvent e) { - if(e.getSource().equals(open) || e.getSource().equals(openInMemory)){ - ArrayList filesToOpen = new ArrayList<>(); - for(int row: exportListTable.getSelectedRows()){ - String uri = n5ExportTableModel.getRowData(row).uri; - SimResultsLoader simResultsLoader = new SimResultsLoader(uri, n5ExportTableModel.getRowData(row).savedFileName); - filesToOpen.add(simResultsLoader); - } - SimResultsLoader.openN5FileDataset(filesToOpen, e.getSource().equals(openInMemory)); - } else if (e.getSource().equals(copyLink)) { - ExportDataRepresentation.SimulationExportDataRepresentation selectedRow = n5ExportTableModel.getRowData(exportListTable.getSelectedRow()); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(new StringSelection(selectedRow.uri), null); - } else if (e.getSource().equals(refreshButton)) { - initalizeTableData(); - } else if (e.getSource().equals(questionMark)) { - new HelpExplanation().displayHelpMenu(); - } else if (e.getSource().equals(useN5Link)) { - remoteFileSelection.setVisible(true); - } else if (e.getSource().equals(openLocal)){ // This button is not displayed to the end user - ArrayList filesToOpen = new ArrayList<>(); - for(int row: exportListTable.getSelectedRows()){ - String uri = n5ExportTableModel.getRowData(row).uri; - SimResultsLoader simResultsLoader = new SimResultsLoader(uri, n5ExportTableModel.getRowData(row).savedFileName); - filesToOpen.add(simResultsLoader); - } - SimResultsLoader.openLocalN5FS(filesToOpen); - } - else if (e.getSource().equals(includeExampleExports)){ - if(includeExampleExports.isSelected()){ - updateExampleExportsToTable(); - return; - } - initalizeTableData(); - } else if (e.getSource().equals(anyInterval) || e.getSource().equals(todayInterval) - || e.getSource().equals(monthInterval) || e.getSource().equals(yearlyInterval)) { - if(includeExampleExports.isSelected()){ - updateExampleExportsToTable(); - return; - } - initalizeTableData(); + return currentRow; + } else { + return findLoadingRow(currentRow + 1, initialRow); } } @Override public void valueChanged(ListSelectionEvent e) { int row = exportListTable.getSelectedRow(); + exportDetailsPanel.resetExportDetails(); if (row > exportListTable.getRowCount() || row < 0){ - parameterTableModel.resetTableData(); - variableTextPanel.setText(""); - open.setEnabled(false); - copyLink.setEnabled(false); - openInMemory.setEnabled(false); - setEnableParentAndChild(exportDetails, false); + controlPanel.enableRowContextDependentButtons(false); return; } - open.setEnabled(true); - copyLink.setEnabled(true); - openInMemory.setEnabled(true); - setEnableParentAndChild(exportDetails, true); -// AttributeSet attributeSet = styleContext.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.) + controlPanel.enableRowContextDependentButtons(true); + MainPanel.setEnableParentAndChild(exportDetailsPanel, true); ExportDataRepresentation.SimulationExportDataRepresentation rowData = n5ExportTableModel.getRowData(row); - variableTextPanel.setText("Variables: " + rowData.variables); - - parameterTableModel.resetTableData(); - for(String parameterValues : rowData.differentParameterValues){ - String[] tokens = parameterValues.split(":"); - parameterTableModel.addRowData(tokens[0], tokens[1], tokens[2]); - } + exportDetailsPanel.addExportDetailEntries("Variables: " + rowData.variables, rowData.differentParameterValues); - variableTextPanel.updateUI(); - parameterTable.updateUI(); + int loadingRow = loadingRowsJobID.containsKey(row) ? findLoadingRow(row, row) : -1; + controlPanel.allowCancel(loadingRow != -1); } + public void removeFromLoadingRows(){ + int row = exportListTable.getSelectedRow(); + N5ImageHandler.loadingFactory.stopOpeningSimulation(n5ExportTableModel.tableData.get(row).jobID); + loadingRowsJobID.remove(row); + exportListTable.repaint(); + } - static class ParameterTableModel extends AbstractTableModel{ - - private final static String parameterHeader = "Parameter"; - private final static String defaultValueHeader = "Default Value"; - private final static String newValueHeader = "New Value"; - - - private List> tableData = new ArrayList<>(); - private final ArrayList headers = new ArrayList(){{ - add(parameterHeader); - add(defaultValueHeader); - add(newValueHeader); - }}; - @Override - public String getColumnName(int column) { - return headers.get(column); - } - - @Override - public int getRowCount() { - return tableData.size(); - } - - @Override - public int getColumnCount() { - return headers.size(); - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - HashMap rowData = tableData.get(rowIndex); - if(columnIndex == headers.indexOf(parameterHeader)){ - return rowData.get(parameterHeader); - } else if (columnIndex == headers.indexOf(defaultValueHeader)) { - return rowData.get(defaultValueHeader); - } else if (columnIndex == headers.indexOf(newValueHeader)) { - return rowData.get(newValueHeader); - } - return null; - } - - public void addRowData(String parameterName, String defaultValue, String newValue){ - HashMap data = new HashMap(){{ - put(parameterHeader, parameterName); - put(defaultValueHeader, defaultValue); - put(newValueHeader, newValue); - }}; - tableData.add(data); - } - - public void resetTableData(){ - tableData = new ArrayList<>(); - } + @Override + public void simIsLoading(int itemRow, String exportID) { + loadingRowsJobID.put(itemRow, exportID); + exportListTable.repaint(); + } + @Override + public void simFinishedLoading(int itemRow, String exportID) { + loadingRowsJobID.remove(itemRow); + exportListTable.repaint(); + controlPanel.allowCancel(false); } static class N5ExportTableModel extends AbstractTableModel { diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/ImageIntoMemory.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java similarity index 64% rename from view-simulation-results/src/main/java/org/vcell/N5/UI/ImageIntoMemory.java rename to view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java index 3735deb..feb47c8 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/UI/ImageIntoMemory.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/RangeSelector.java @@ -1,10 +1,7 @@ package org.vcell.N5.UI; -import ij.ImagePlus; -import ij.plugin.Duplicator; import org.scijava.log.Logger; import org.vcell.N5.N5ImageHandler; -import org.vcell.N5.SimResultsLoader; import javax.swing.*; import javax.swing.event.EventListenerList; @@ -13,9 +10,8 @@ import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; -import java.io.IOException; -public class ImageIntoMemory extends EventListenerList implements ActionListener { +public class RangeSelector extends JDialog implements ActionListener { public int startC; public int endC; public int startT; @@ -30,15 +26,20 @@ public class ImageIntoMemory extends EventListenerList implements ActionListener private final JTextField zStartTextField; private final JTextField zEndTextField; - private final JButton okayButton; - private final JButton cancelButton; + public boolean cancel; + + private static final String okayButtonText = "Okay"; + private static final String cancelButtonText = "Cancel"; + public final JButton okayButton; + public final JButton cancelButton; private final JFrame frame; - private final SimResultsLoader simResultsLoader; - private static final Logger logger = N5ImageHandler.getLogger(ImageIntoMemory.class); + private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class); + private static final EventListenerList eventListenerList = new EventListenerList(); + + private final ControlButtonsPanel controlButtonsPanel = MainPanel.controlButtonsPanel; - public ImageIntoMemory(double cDim, double zDim, double tDim, SimResultsLoader simResultsLoader){ - this.simResultsLoader = simResultsLoader; + public RangeSelector(double cDim, double zDim, double tDim, String userSetFileName){ channelStartTextField = new HintTextField("1"); channelEndTextField = new HintTextField("" + (int) cDim); @@ -49,9 +50,10 @@ public ImageIntoMemory(double cDim, double zDim, double tDim, SimResultsLoader s timeEndTextField = new HintTextField("" + (int) tDim); // Create the frame - frame = new JFrame("Select " + simResultsLoader.userSetFileName + " Dimensions"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setSize(400, 200); + frame = new JFrame("Select " + userSetFileName + " Dimensions"); + this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + this.setSize(400, 200); + this.setTitle("Select " + userSetFileName + " Dimensions"); // Create a panel to hold the input boxes and buttons JPanel panel = new JPanel(); @@ -75,8 +77,8 @@ public ImageIntoMemory(double cDim, double zDim, double tDim, SimResultsLoader s // Create the "Okay" and "Cancel" buttons panel.add(new JLabel()); - okayButton = new JButton("Okay"); - cancelButton = new JButton("Cancel"); + okayButton = new JButton(okayButtonText); + cancelButton = new JButton(cancelButtonText); // Add action listeners to the buttons okayButton.addActionListener(this); @@ -89,30 +91,22 @@ public ImageIntoMemory(double cDim, double zDim, double tDim, SimResultsLoader s // Add the panel to the frame frame.add(panel); + this.setContentPane(panel); + this.setModal(true); } public void displayRangeMenu(){ // Make the window visible - frame.setVisible(true); - } - - public static void usePopUp(){ - - } - - public static void useExistingParameters(int startC, int endC, int startT, int endT, int startZ, int endZ){ - + this.setVisible(true); } public static void main(String[] args) { - ImageIntoMemory inMemoryPopUp = new ImageIntoMemory(1, 2, 3, null); + RangeSelector inMemoryPopUp = new RangeSelector(1, 2, 3, null); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource().equals(okayButton)){ - frame.dispose(); - startC = Integer.parseInt(channelStartTextField.getText()); endC = Integer.parseInt(channelEndTextField.getText()); startT = Integer.parseInt(timeStartTextField.getText()) - 1; @@ -120,31 +114,17 @@ public void actionPerformed(ActionEvent e) { startZ = Integer.parseInt(zStartTextField.getText()) - 1; endZ = Integer.parseInt(zEndTextField.getText()) - 1; - Thread openInMemory = new Thread(() -> { - try { - ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File(); - long start = System.currentTimeMillis(); - logger.debug("Loading Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory"); - imagePlus = new Duplicator().run(imagePlus, startC, endC, startZ, - endZ, startT, endT); - long end = System.currentTimeMillis(); - logger.debug("Loaded Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory taking: " + ((end - start)/ 1000) + "s"); - imagePlus.show(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } finally { - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - N5ExportTable.enableCriticalButtons(true); - } - }); - openInMemory.setName("Open N5 Image in Memory"); - openInMemory.start(); + cancel = false; + + this.setVisible(false); + this.setModal(false); } else if (e.getSource().equals(cancelButton)) { - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - N5ExportTable.enableCriticalButtons(true); - frame.dispose(); + MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + controlButtonsPanel.enableCriticalButtons(true); + cancel = true; + this.setVisible(false); } } diff --git a/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java b/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java index be90e61..6f0f827 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/UI/RemoteFileSelection.java @@ -1,6 +1,7 @@ package org.vcell.N5.UI; -import org.vcell.N5.SimResultsLoader; +import org.vcell.N5.N5ImageHandler; +import org.vcell.N5.retrieving.SimResultsLoader; import javax.swing.*; import java.awt.*; @@ -94,8 +95,8 @@ public String getS3URL(){ @Override public void actionPerformed(ActionEvent e) { - SimResultsLoader simResultsLoader = new SimResultsLoader(getS3URL(), ""); - SimResultsLoader.openN5FileDataset(new ArrayList(){{add(simResultsLoader);}}, N5ExportTable.openInMemory.isSelected()); + SimResultsLoader simResultsLoader = new SimResultsLoader(getS3URL(), "", -1, ""); + N5ImageHandler.loadingFactory.openN5FileDataset(new ArrayList(){{add(simResultsLoader);}}, false); this.setVisible(false); } } diff --git a/view-simulation-results/src/main/java/org/vcell/N5/S3KeyValueAccess.java b/view-simulation-results/src/main/java/org/vcell/N5/library/extensions/S3KeyValueAccess.java similarity index 94% rename from view-simulation-results/src/main/java/org/vcell/N5/S3KeyValueAccess.java rename to view-simulation-results/src/main/java/org/vcell/N5/library/extensions/S3KeyValueAccess.java index df019bd..a615d01 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/S3KeyValueAccess.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/library/extensions/S3KeyValueAccess.java @@ -1,12 +1,9 @@ -package org.vcell.N5; +package org.vcell.N5.library.extensions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.ListObjectsV2Request; import org.janelia.saalfeldlab.n5.N5Exception; import org.janelia.saalfeldlab.n5.s3.AmazonS3KeyValueAccess; -import org.janelia.saalfeldlab.n5.s3.AmazonS3Utils; - -import java.net.URI; public class S3KeyValueAccess extends AmazonS3KeyValueAccess { private final String bucketName; diff --git a/view-simulation-results/src/main/java/org/vcell/N5/SimCacheLoader.java b/view-simulation-results/src/main/java/org/vcell/N5/library/extensions/SimCacheLoader.java similarity index 98% rename from view-simulation-results/src/main/java/org/vcell/N5/SimCacheLoader.java rename to view-simulation-results/src/main/java/org/vcell/N5/library/extensions/SimCacheLoader.java index b8c24a6..60bf8dc 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/SimCacheLoader.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/library/extensions/SimCacheLoader.java @@ -1,4 +1,4 @@ -package org.vcell.N5; +package org.vcell.N5.library.extensions; import ij.ImagePlus; import ij.gui.ImageWindow; diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java new file mode 100644 index 0000000..a673257 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/LoadingFactory.java @@ -0,0 +1,153 @@ +package org.vcell.N5.retrieving; + +import com.amazonaws.AbortedException; +import com.amazonaws.http.timers.client.SdkInterruptedException; +import ij.ImagePlus; +import ij.plugin.Duplicator; +import org.scijava.log.Logger; +import org.vcell.N5.N5ImageHandler; +import org.vcell.N5.UI.ControlButtonsPanel; +import org.vcell.N5.UI.RangeSelector; +import org.vcell.N5.UI.MainPanel; + +import javax.swing.*; +import javax.swing.event.EventListenerList; +import java.awt.*; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; + +public class LoadingFactory implements SimLoadingEventCreator { + private static final EventListenerList eventListenerList = new EventListenerList(); + + private final ControlButtonsPanel controlButtonsPanel = MainPanel.controlButtonsPanel; + + private final HashMap openingSimulations = new HashMap<>(); + private final Object openSimulationsLock = new Object(); + + private static final Logger logger = N5ImageHandler.getLogger(RangeSelector.class); + + public void openN5FileDataset(ArrayList filesToOpen, boolean openInMemory){ + controlButtonsPanel.allowCancel(true); + MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR)); + + for (int i = 0; i < filesToOpen.size(); i++){ + SimResultsLoader simResultsLoader = filesToOpen.get(i); + Thread openThread = new Thread(() -> { + try{ + simResultsLoader.createS3ClientAndReader(); + notifySimIsLoading(simResultsLoader); + RangeSelector rangeSelector; + if (openInMemory){ + ArrayList dimensions = simResultsLoader.getN5Dimensions(); + rangeSelector = new RangeSelector(dimensions.get(2), dimensions.get(3), dimensions.get(4), simResultsLoader.userSetFileName); + rangeSelector.displayRangeMenu(); + if (!rangeSelector.cancel){ + openInMemory(simResultsLoader, rangeSelector); + } + rangeSelector.dispose(); + } else{ + ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File(); + imagePlus.show(); + } + } + catch (RuntimeException e) { + if (e.getCause().getCause().getCause() instanceof SdkInterruptedException || + e.getCause().getCause() instanceof AbortedException){ + logger.debug("Simulation stopped loading"); + } else { + throw new RuntimeException(e); + } + } + catch (Exception e){ + throw new RuntimeException(e); + } finally { + MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + controlButtonsPanel.enableCriticalButtons(true); + notifySimIsDoneLoading(simResultsLoader); + synchronized (openSimulationsLock){ + openingSimulations.remove(simResultsLoader.exportID); + } + } + }); + openThread.setName("Opening sim number: " + i + ". With id: " + simResultsLoader.exportID); + synchronized (openSimulationsLock){ + openingSimulations.put(simResultsLoader.exportID, openThread); + } + openThread.start(); + } + } + + private void openInMemory(SimResultsLoader simResultsLoader, RangeSelector rangeSelector) throws IOException { + ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File(); + long start = System.currentTimeMillis(); + logger.debug("Loading Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory"); + imagePlus = new Duplicator().run(imagePlus, rangeSelector.startC, rangeSelector.endC, rangeSelector.startZ, + rangeSelector.endZ, rangeSelector.startT, rangeSelector.endT); + long end = System.currentTimeMillis(); + logger.debug("Loaded Virtual N5 File " + simResultsLoader.userSetFileName + " Into Memory taking: " + ((end - start)/ 1000) + "s"); + imagePlus.show(); + } + + public void stopOpeningSimulation(String exportID){ + Thread stopOtherThread = new Thread(() -> { + synchronized (openSimulationsLock){ + openingSimulations.get(exportID).interrupt(); + openingSimulations.remove(exportID); + } + }); + stopOtherThread.start(); + } + + public void openLocalN5FS(ArrayList filesToOpen){ + controlButtonsPanel.enableCriticalButtons(true); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + fileChooser.setAcceptAllFileFilterUsed(false); + int result = fileChooser.showOpenDialog(null); + if (result == JFileChooser.APPROVE_OPTION){ + File file = fileChooser.getSelectedFile(); + MainPanel.changeCursor(new Cursor(Cursor.WAIT_CURSOR)); + Thread openN5FileDataset = new Thread(() -> { + try{ + for(SimResultsLoader simResultsLoader: filesToOpen){ + simResultsLoader.setSelectedLocalFile(file); + ImagePlus imagePlus = simResultsLoader.getImgPlusFromLocalN5File(); + imagePlus.show(); + } + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + MainPanel.changeCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + controlButtonsPanel.enableCriticalButtons(true); + } + }); + } + }); + openN5FileDataset.start(); + } + } + + @Override + public void addSimLoadingListener(SimLoadingListener simLoadingListener) { + eventListenerList.add(SimLoadingListener.class, simLoadingListener); + } + + @Override + public void notifySimIsLoading(SimResultsLoader simResultsLoader) { + for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){ + simLoadingListener.simIsLoading(simResultsLoader.rowNumber, simResultsLoader.exportID); + } + } + + @Override + public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader) { + for (SimLoadingListener simLoadingListener: eventListenerList.getListeners(SimLoadingListener.class)){ + simLoadingListener.simFinishedLoading(simResultsLoader.rowNumber, simResultsLoader.exportID); + } + } +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java new file mode 100644 index 0000000..2a0a357 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingEventCreator.java @@ -0,0 +1,10 @@ +package org.vcell.N5.retrieving; + +public interface SimLoadingEventCreator { + public void addSimLoadingListener(SimLoadingListener simLoadingListener); + + public void notifySimIsLoading(SimResultsLoader simResultsLoader); + + public void notifySimIsDoneLoading(SimResultsLoader simResultsLoader); + +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java new file mode 100644 index 0000000..d2ddf09 --- /dev/null +++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimLoadingListener.java @@ -0,0 +1,11 @@ +package org.vcell.N5.retrieving; + +import java.util.EventListener; + +public interface SimLoadingListener extends EventListener { + + public void simIsLoading(int itemRow, String exportID); + + public void simFinishedLoading(int itemRow, String exportID); + +} diff --git a/view-simulation-results/src/main/java/org/vcell/N5/SimResultsLoader.java b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java similarity index 72% rename from view-simulation-results/src/main/java/org/vcell/N5/SimResultsLoader.java rename to view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java index 36ff0cb..a3e9495 100644 --- a/view-simulation-results/src/main/java/org/vcell/N5/SimResultsLoader.java +++ b/view-simulation-results/src/main/java/org/vcell/N5/retrieving/SimResultsLoader.java @@ -1,4 +1,4 @@ -package org.vcell.N5; +package org.vcell.N5.retrieving; import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSStaticCredentialsProvider; @@ -10,7 +10,6 @@ import com.google.gson.GsonBuilder; import ij.ImagePlus; import ij.plugin.ContrastEnhancer; -import ij.plugin.frame.ContrastAdjuster; import net.imglib2.cache.img.CachedCellImg; import net.imglib2.img.display.imagej.ImageJFunctions; import net.imglib2.type.numeric.real.DoubleType; @@ -24,14 +23,13 @@ import org.janelia.saalfeldlab.n5.imglib2.N5Utils; import org.janelia.saalfeldlab.n5.s3.N5AmazonS3Reader; import org.scijava.log.Logger; -import org.vcell.N5.UI.N5ExportTable; -import org.vcell.N5.UI.ImageIntoMemory; +import org.vcell.N5.N5ImageHandler; +import org.vcell.N5.library.extensions.S3KeyValueAccess; +import org.vcell.N5.library.extensions.SimCacheLoader; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; -import javax.swing.*; -import java.awt.*; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -57,9 +55,16 @@ public class SimResultsLoader { private static final Logger logger = N5ImageHandler.getLogger(SimResultsLoader.class); public static AmazonS3ClientBuilder s3ClientBuilder; + public int rowNumber; + public String exportID; public SimResultsLoader(){ + } + public SimResultsLoader(String stringURI, String userSetFileName, int rowNumber, String exportID){ + this(stringURI, userSetFileName); + this.rowNumber = rowNumber; + this.exportID = exportID; } public SimResultsLoader(String stringURI, String userSetFileName){ uri = URI.create(stringURI); @@ -165,77 +170,6 @@ public ArrayList getN5Dimensions(){ return n5AmazonS3Reader.getAttribute(dataSetChosen, "dimensions", ArrayList.class); } - - public static void openN5FileDataset(ArrayList filesToOpen, boolean openInMemory){ - N5ExportTable.enableCriticalButtons(false); - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.WAIT_CURSOR)); - Thread openN5FileDataset = new Thread(() -> { - try{ - for(SimResultsLoader simResultsLoader: filesToOpen){ - simResultsLoader.createS3ClientAndReader(); - ImageIntoMemory imageIntoMemory; - if (openInMemory){ - ArrayList dimensions = simResultsLoader.getN5Dimensions(); - imageIntoMemory = new ImageIntoMemory(dimensions.get(2), dimensions.get(3), dimensions.get(4), simResultsLoader); - imageIntoMemory.displayRangeMenu(); - } else{ - ImagePlus imagePlus = simResultsLoader.getImgPlusFromN5File(); - imagePlus.show(); - } - - } - } catch (Exception ex) { - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - N5ExportTable.enableCriticalButtons(true); - throw new RuntimeException(ex); - } finally { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (!openInMemory) { - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - N5ExportTable.enableCriticalButtons(true); - } - } - }); - } - }); - openN5FileDataset.setName("Open N5 File"); - openN5FileDataset.start(); - } - - public static void openLocalN5FS(ArrayList filesToOpen){ - N5ExportTable.enableCriticalButtons(true); - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - fileChooser.setAcceptAllFileFilterUsed(false); - int result = fileChooser.showOpenDialog(null); - if (result == JFileChooser.APPROVE_OPTION){ - File file = fileChooser.getSelectedFile(); - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.WAIT_CURSOR)); - Thread openN5FileDataset = new Thread(() -> { - try{ - for(SimResultsLoader simResultsLoader: filesToOpen){ - simResultsLoader.setSelectedLocalFile(file); - ImagePlus imagePlus = simResultsLoader.getImgPlusFromLocalN5File(); - imagePlus.show(); - } - } catch (IOException ex) { - throw new RuntimeException(ex); - } finally { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - N5ExportTable.exportTableDialog.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - N5ExportTable.enableCriticalButtons(true); - } - }); - } - }); - openN5FileDataset.start(); - } - } - void setDataSetChosen(String dataSetChosen) { this.dataSetChosen = dataSetChosen; } diff --git a/view-simulation-results/src/test/java/org/vcell/N5/N5ImageHandlerTest.java b/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java similarity index 99% rename from view-simulation-results/src/test/java/org/vcell/N5/N5ImageHandlerTest.java rename to view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java index 1f19578..1403cb3 100644 --- a/view-simulation-results/src/test/java/org/vcell/N5/N5ImageHandlerTest.java +++ b/view-simulation-results/src/test/java/org/vcell/N5/retrieving/N5ImageHandlerTest.java @@ -1,4 +1,4 @@ -package org.vcell.N5; +package org.vcell.N5.retrieving; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.google.gson.internal.LinkedTreeMap; @@ -11,6 +11,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.vcell.N5.N5DataSetFile; +import org.vcell.N5.N5ImageHandler; import java.io.File; import java.io.IOException;