package edu.mssm.pharm.maayanlab.Enrichr; import java.awt.Desktop; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.text.DecimalFormat; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTree; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeSelectionModel; import edu.mssm.pharm.maayanlab.Enrichr.ResourceLoader.EnrichmentCategory; import edu.mssm.pharm.maayanlab.Enrichr.ResourceLoader.EnrichmentLibrary; import edu.mssm.pharm.maayanlab.common.bio.EnrichedTerm; import edu.mssm.pharm.maayanlab.common.core.FileUtils; import edu.mssm.pharm.maayanlab.common.core.SettingsChanger; import edu.mssm.pharm.maayanlab.common.swing.FileDrop; import edu.mssm.pharm.maayanlab.common.swing.UIUtils; public class EnrichrPanel extends JPanel { static Logger log = Logger.getLogger(EnrichrPanel.class.getSimpleName()); private static final long serialVersionUID = 7312294713338308079L; // L2N process holder to call from nested class private EnrichrBatcher app; // Tree for tree pane private JTree tree; // JPanels private JPanel panel; // UI elements private JFileChooser openChooser, saveChooser; private JTextField openPath, savePath; private JTextArea inputTextArea; private JButton viewButton, runButton; private ProgressMonitor progressMonitor; // progress bar // Checkboxes for the different databases private ArrayList<JCheckBox> checkboxes = new ArrayList<JCheckBox>(); // Formatter for scientific notation private final DecimalFormat scientificNotation = new DecimalFormat("0.##E0"); private String output; // output string public static void main(String[] args) { if (args.length == 0) { // Schedule a job for the EDT SwingUtilities.invokeLater(new Runnable() { @Override public void run() { createAndShowGUI(); } }); } else{ EnrichrBatcher.main(args); } } private static void createAndShowGUI() { // Try to use Nimbus look and feel try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) { log.warning("Nimbus: " + e); } // Create and set up the window JFrame appFrame = new JFrame("Enrichr"); appFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Add content to the window EnrichrPanel appPanel = new EnrichrPanel(); appFrame.setContentPane(appPanel); // Display the window appFrame.setResizable(false); appFrame.pack(); appFrame.setVisible(true); } public EnrichrPanel() { this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); if (!Boolean.getBoolean("verbose")) log.setLevel(Level.WARNING); // Attach instance to variable so nested classes can reference it panel = this; // File choosers openChooser = new JFileChooser(System.getProperty("user.dir")); openChooser.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { File file = openChooser.getSelectedFile(); if (file != null && file.canRead() && e.getActionCommand().equals(JFileChooser.APPROVE_SELECTION)) setupIO(file); } }); saveChooser = new JFileChooser(System.getProperty("user.dir")); saveChooser.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { File file = saveChooser.getSelectedFile(); if (file != null && e.getActionCommand().equals(JFileChooser.APPROVE_SELECTION)) { if (!file.getName().endsWith(".xml")) { file = new File(file.getAbsolutePath() + ".xml"); saveChooser.setSelectedFile(file); } savePath.setText(file.getAbsolutePath()); } } }); // Select input/output file button JButton openFileButton = new JButton("Input Genes"); openFileButton.setPreferredSize(new Dimension(300, 30)); openFileButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { openChooser.showOpenDialog(panel); } }); JButton saveFileButton = new JButton("Output Summary"); saveFileButton.setPreferredSize(new Dimension(300, 30)); saveFileButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveChooser.showSaveDialog(panel); } }); // Text fields openPath = new JTextField(); savePath = new JTextField(); // File Drop new FileDrop(openPath, new FileDrop.Listener() { @Override public void filesDropped(File[] files) { if (files[0].canRead()) { setupIO(files[0]); openChooser.setSelectedFile(files[0]); } } }); // Tree tree = new JTree(new DefaultMutableTreeNode("Ready to enrich!")); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setShowsRootHandles(true); // Scroll panes inputTextArea = new JTextArea(20, 20); JScrollPane inputTextPane = new JScrollPane(inputTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); inputTextPane.setPreferredSize(new Dimension(300, 300)); JScrollPane outputTreePane = new JScrollPane(tree, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); outputTreePane.setPreferredSize(new Dimension(300, 300)); // File Drop new FileDrop(inputTextArea, new FileDrop.Listener() { @Override public void filesDropped(File[] files) { if (files[0].canRead()) { setupIO(files[0]); openChooser.setSelectedFile(files[0]); } } }); // Start button runButton = new JButton("Find Enriched Terms"); runButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { output = savePath.getText(); if (!output.equals("")) { app = new EnrichrBatcher(); setSettings(app); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Currently running enrichment analysis... please wait."); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); tree.setModel(treeModel); tree.setRootVisible(true); progressMonitor = new ProgressMonitor(panel, "Running Enrichment Analaysis", "", 0, 100); progressMonitor.setMillisToDecideToPopup(0); progressMonitor.setProgress(0); final Task task = new Task(); app.setTask(task); task.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress" == evt.getPropertyName()) { int progress = (Integer) evt.getNewValue(); progressMonitor.setProgress(progress); } else if ("note" == evt.getPropertyName()) { String message = (String) evt.getNewValue(); progressMonitor.setNote(message); } if (progressMonitor.isCanceled()) { task.cancel(true); app.cancel(); } } }); task.execute(); runButton.setEnabled(false); } else { JOptionPane.showMessageDialog(panel, "No save location specified.", "No Save Location", JOptionPane.WARNING_MESSAGE); } } }); // View Button viewButton = new JButton("View Results"); viewButton.setEnabled(false); viewButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { Desktop.getDesktop().open(new File(output)); } catch (Exception e1) { JOptionPane.showMessageDialog(panel, "Unable to open " + output, "Unable to open file", JOptionPane.ERROR_MESSAGE); } } }); // Advanced Settings JPanel bgBox = new JPanel(); JLabel bgLabel = new JLabel("<html>Select<br>enrichment:</html>"); bgLabel.setHorizontalAlignment(JLabel.LEFT); bgBox.add(bgLabel); JPanel checkboxBox = new JPanel(new GridLayout(0, 3)); for (EnrichmentCategory category : ResourceLoader.getInstance().getCategories()) { for (EnrichmentLibrary library : category.getLibraries()) { JCheckBox checkbox = new JCheckBox(library.getName().replace("_", " "), true); checkboxes.add(checkbox); checkboxBox.add(checkbox); } } bgBox.add(checkboxBox); // Input and output box JPanel ioBox = new JPanel(); ioBox.setLayout(new GridLayout(2,2)); ioBox.add(openFileButton); ioBox.add(saveFileButton); ioBox.add(openPath); ioBox.add(savePath); // Panes JPanel textPanesBox = new JPanel(); textPanesBox.setLayout(new BoxLayout(textPanesBox, BoxLayout.LINE_AXIS)); textPanesBox.add(inputTextPane); textPanesBox.add(outputTreePane); // Button box JPanel buttonBox = new JPanel(); buttonBox.setLayout(new BoxLayout(buttonBox, BoxLayout.LINE_AXIS)); buttonBox.add(runButton); buttonBox.add(viewButton); // Advanced settings box JPanel advancedSettingsBox = new JPanel(); advancedSettingsBox.setLayout(new BoxLayout(advancedSettingsBox, BoxLayout.PAGE_AXIS)); advancedSettingsBox.setBorder(BorderFactory.createTitledBorder("Advanced Settings")); advancedSettingsBox.add(bgBox); // Add all the panels together this.add(ioBox); this.add(textPanesBox); this.add(Box.createRigidArea(new Dimension(0,10))); this.add(buttonBox); this.add(advancedSettingsBox); } public void setSettings(SettingsChanger changer) { for (JCheckBox checkbox : checkboxes) { changer.setSetting(checkbox.getText().replace(" ", "_"), Boolean.toString(checkbox.isSelected())); } } public void setInputTextArea(Collection<String> list) { UIUtils.setTextAreaText(inputTextArea, list); } // Allow X2K to set output file public void setupIO(File inputFile) { openPath.setText(inputFile.getAbsolutePath()); UIUtils.setTextAreaText(inputTextArea, FileUtils.readFile(inputFile)); File outputFile = new File(System.getProperty("user.dir"), FileUtils.stripFileExtension(inputFile.getName()) + ".enrichment.xml"); saveChooser.setSelectedFile(outputFile); savePath.setText(outputFile.getAbsolutePath()); } public void updateTree(HashMap<String, ArrayList<EnrichedTerm>> resultsMap) { DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel(); DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) treeModel.getRoot(); for (String bgType : resultsMap.keySet()) { DefaultMutableTreeNode categoryNode = new DefaultMutableTreeNode(bgType); treeModel.insertNodeInto(categoryNode, rootNode, rootNode.getChildCount()); rootNode.add(categoryNode); for (EnrichedTerm term : resultsMap.get(bgType)) { DefaultMutableTreeNode termNode = new DefaultMutableTreeNode(term.getName() + " (" + scientificNotation.format(term.getPValue()) + ")"); treeModel.insertNodeInto(termNode, categoryNode, categoryNode.getChildCount()); categoryNode.add(termNode); } } } class Task extends SwingWorker<Void, Void> { @Override protected Void doInBackground() throws Exception { try { app.run(UIUtils.getTextAreaText(inputTextArea)); } catch (ParseException e1) { JOptionPane.showMessageDialog(panel, e1.getMessage().replace("Invalid Input", ""), "Invalid Input", JOptionPane.WARNING_MESSAGE); } try { Thread.sleep(500); setProgress(100); } catch(InterruptedException e ) { } return null; } @Override public void done() { if (isCancelled()) { cancelled(); } else { // Update tree updateTree(app.getEnrichmentResults()); tree.expandRow(0); tree.setRootVisible(false); // Output app.writeFile(output); // io is expensive so do last // UI clean up runButton.setEnabled(true); if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) viewButton.setEnabled(true); } } private void cancelled() { DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Last run was cancelled."); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); tree.setModel(treeModel); tree.setRootVisible(true); runButton.setEnabled(true); } } }