package gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import model.ErrorLogger; import util.AnnotationDataType; import util.AnnotationDataValue; import util.ExperimentData; import util.FileDrop; import util.GenomeReleaseData; public class UploadExpPanel extends JPanel implements ExperimentPanel { private static final long serialVersionUID = 7664913630434090250L; private HashMap<File, UploadFileRow> uploadFileRows; private HashMap<String, JComboBox<String>> annotationBoxes; private HashMap<String, JTextField> annotationFields; private HashMap<String, JPanel> currentAnnotations; private ArrayList<String> annotationHeaders; private JPanel uploadFilesPanel, newExpPanel, buttonsPanel, uploadBackground; private JButton uploadButton, uploadSelectedBtn, selectButton; private AnnotationDataType[] annotations; private JLabel expNameLabel, boldTextLabel; private JComboBox<String> species; private JTextField expID; private ArrayList<String> genome; private GridBagConstraints gbc; private boolean isNewExp; public void toggleFields(boolean bool) { expID.setEnabled(bool); for (String string : annotationHeaders) { if (annotationBoxes.containsKey(string)) { annotationBoxes.get(string).setEnabled(bool); } else if(annotationFields.containsKey(string)){ annotationFields.get(string).setEnabled(bool); } } } /** * Constructor initiating the new experiment panel. */ public UploadExpPanel() { setLayout(new BorderLayout()); uploadFileRows = new HashMap<File, UploadFileRow>(); annotationBoxes = new HashMap<String, JComboBox<String>>(); annotationFields = new HashMap<String, JTextField>(); annotationHeaders = new ArrayList<String>(); uploadBackground = new JPanel(new BorderLayout()); buttonsPanel = new JPanel(new FlowLayout()); uploadFilesPanel = new JPanel(new GridLayout(0, 1)); selectButton = new JButton(); uploadSelectedBtn = new JButton(); uploadButton = new JButton(); newExpPanel = new JPanel(); expNameLabel = new JLabel(); boldTextLabel = new JLabel( "<html><b>Bold text indicates a forced annotation.</b></html>"); boldTextLabel.setOpaque(true); expNameLabel = new JLabel(); species = new JComboBox<String>(); species.setPreferredSize(new Dimension(120, 31)); expID = new JTextField(); expID.setColumns(10); expID.getDocument().addDocumentListener(new FreetextListener()); genome = new ArrayList<String>(); currentAnnotations = new HashMap<String, JPanel>(); enableUploadButton(false); } /** * Method creating the new experiment panel, with the given annotations to * fill in. * * @param annotations * An array with the current available annotations on the server. * @param isNewExp */ public void createNewExpPanel(AnnotationDataType[] annotations, boolean isNewExp) { clear(); this.annotations = annotations; this.isNewExp = isNewExp; createNewExp(); } /** * Method redefining the removeAll() method of JPanel. Used to clear this * panel. */ @Override public void removeAll() { newExpPanel.removeAll(); uploadBackground.removeAll(); buttonsPanel.removeAll(); uploadFilesPanel.removeAll(); super.removeAll(); } /** * A method returning the current upload file rows. * * @return a Hashmap containing the current UploadFileRows. */ public HashMap<File, UploadFileRow> getFileRows() { return uploadFileRows; } /** * Method returning the current selected species. * * @return a String representing the species. */ public String getSelectedSpecies() { if (species != null) { if (species.getSelectedItem() == null) { return ""; } else { return species.getSelectedItem().toString(); } } else { return ""; } } /** * Return the Entered value of the annotation with this name. * * @param annotationName * To look for * @return The entered value, or null if it doesn't exist */ private String getEnteredAnnotationValue(String annotationName) { if (annotationBoxes.containsKey(annotationName)) { return annotationBoxes.get(annotationName).getSelectedItem() .toString(); } else if (annotationFields.containsKey(annotationName)) { return annotationFields.get(annotationName).getText(); } return null; } /** * Method used to set the current available genome versions, for the chosen * species. * * @param grd * An array containing the current genome releases. */ public void setGenomeReleases(GenomeReleaseData[] grd) { genome.clear(); if (grd.length > 0) { for (GenomeReleaseData g : grd) { try { genome.add(g.getVersion()); } catch (NullPointerException e) { ErrorLogger.log(e); ErrorLogger.log("Couldn't find genome version."); } } } for (File f : uploadFileRows.keySet()) { uploadFileRows.get(f).resetType(); } } /** * Method returning the current available genome releases for the species * selected. * * @return an array of Strings representing the releases. */ public ArrayList<String> getGenomeReleases() { return genome; } /** * Method adding a listener to the "selectButton" button. * * @see controller.UploadTabController#SelectFilesToNewExpListener() * @param listener * The listener to select files. */ public void addSelectButtonListener(ActionListener listener) { selectButton.addActionListener(listener); } /** * Method adding a listener to the "uploadButton" button. * * @see controller.UploadTabController#UploadNewExpListener * @param listener * The listener to start uploading all files. */ public void addUploadButtonListener(ActionListener listener) { uploadButton.addActionListener(listener); } /** * Method adding a listener to the "uploadSelectedBtn" button. * * @param listener * The listener to start uploading selected files. */ public void addUploadSelectedFilesListener(ActionListener listener) { uploadSelectedBtn.addActionListener(listener); } /** * Method adding a listener to the "species" combobox. * * @see controller.UploadTabController#SpeciesSelectedListener() * @param listener * The listener for the species combobox. */ public void addSpeciesSelectedListener(ActionListener listener) { species.addActionListener(listener); } /** * A method creating a panel for creating a new experiment to upload files * to it. */ public void createNewExp() { // TODO: Fix this try NPTR try { GridBagLayout gbl_panel = new GridBagLayout(); gbl_panel.columnWidths = new int[] { 0, 0, 0, 0, 0, 0, 0 }; gbl_panel.rowHeights = new int[] { 0, 0, 0, 0 }; gbl_panel.columnWeights = new double[] { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE }; gbl_panel.rowWeights = new double[] { 0.0, 0.0, 0.0, Double.MIN_VALUE }; newExpPanel.setLayout(gbl_panel); add(newExpPanel, BorderLayout.NORTH); updateAnnotations(annotations); uploadBackground.add(uploadFilesPanel, BorderLayout.NORTH); add(uploadBackground, BorderLayout.CENTER); // Makes dragging & dropping of files into the panel possible new FileDrop(this, new FileDrop.Listener() { public void filesDropped(java.io.File[] files) { createUploadFileRow(files); enableUploadButton(true); } }); } catch (NullPointerException e) { ErrorLogger.log(e); System.err .println("NullPointerException while retrieving annotations from server."); } } /** * Method updating current annotations available at the server. */ public void updateAnnotations(AnnotationDataType[] annotations) { ArrayList<String> exists = new ArrayList<String>(); if (!annotationHeaders.contains("UniqueExpID")) { createUniqueExpIDPanel(); } exists.add("UniqueExpID"); for (AnnotationDataType a : annotations) { if (annotationHeaders.contains(a.getName())) { exists.add(addExcistingAnnotations(a)); } else { exists.add(addNewAnnotation(a)); } } String[] checkIt = new String[annotationHeaders.size()]; for (int i = 0; i < annotationHeaders.size(); i++) { checkIt[i] = annotationHeaders.get(i); } for (String s : checkIt) { if (!exists.contains(s)) { annotationHeaders.remove(s); annotationFields.remove(s); annotationBoxes.remove(s); currentAnnotations.remove(s); } exists.remove(s); } buildAnnotationsMenu(); this.annotations = annotations; } /** * Method that creates and adds a new annotation * * @param a * - Annotation to add * @return Name of created annotation */ private String addNewAnnotation(AnnotationDataType a) { JPanel p = new JPanel(new BorderLayout()); JLabel annotationLabel = null; if (a.isForced()) { annotationLabel = new JLabel("<html><b>" + a.getName() + "</b></html>"); annotationLabel .setToolTipText("Bold indicates a forced annotation"); } else { annotationLabel = new JLabel(a.getName()); } annotationHeaders.add(a.getName()); p.add(annotationLabel, BorderLayout.NORTH); if (a.getValues().length == 1 && a.getValues()[0].equalsIgnoreCase("freetext")) { final JTextField textField = createAnnotationTextField(); annotationFields.put(a.getName(), textField); p.add(textField, BorderLayout.CENTER); } else { final JComboBox<String> comboBox = createAnnotationComboBox(a); annotationBoxes.put(a.getName(), comboBox); p.add(comboBox, BorderLayout.CENTER); } currentAnnotations.put(a.getName(), p); return a.getName(); } /** * Method that creates a new combo box for annotations and filles it with * values and an empty row as first alternative. Enabled if isNewExp * * @param a * - Annotation to create combo box for * @return A JComboBox */ private JComboBox<String> createAnnotationComboBox(AnnotationDataType a) { final JComboBox<String> comboBox; if (a.getName().equalsIgnoreCase("species")) { comboBox = species; species.removeAllItems(); for (String s : a.getValues()) { species.addItem(s); } species.setSelectedIndex(0); } else { comboBox = new JComboBox<String>(a.getValues()); } comboBox.setPreferredSize(new Dimension(120, 31)); // Listener for when the user chooses something in the combobox comboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { enableUploadButton(forcedAnnotationCheck()); } }); return comboBox; } /** * Creates an annotation text field. Enabled if isNewExp * * @return */ private JTextField createAnnotationTextField() { final JTextField textField = new JTextField(); textField.setColumns(10); // Add listener for when the text in the textfield changes. textField.getDocument().addDocumentListener(new FreetextListener()); return textField; } /** * Updates and adds an already known annotation * * @param a * - Annotation to add * @return Name of added annotation */ private String addExcistingAnnotations(AnnotationDataType a) { if (a.getValues().length == 1 && a.getValues()[0].equalsIgnoreCase("freetext")) { return a.getName(); } else if (annotationBoxes.containsKey(a.getName())) { JComboBox<String> currentBox = annotationBoxes.get(a.getName()); // +1 for emty item. if (a.getValues().length + 1 == currentBox.getItemCount()) { return a.getName(); } else { currentBox.removeAllItems(); String[] aCopy = new String[a.getValues().length]; for (int i = 0; i < a.getValues().length; i++) { aCopy[i] = a.getValues()[i]; } for (String s : aCopy) { currentBox.addItem(s); } return a.getName(); } } else { return addNewAnnotation(a); } } /** * Creates a Experiment ID panel if non exist */ private void createUniqueExpIDPanel() { JPanel exp = new JPanel(new BorderLayout()); expNameLabel.setText("<html><b>Experiment ID</b></html>"); expNameLabel.setToolTipText("Bold indicates a forced annotation"); exp.add(expNameLabel, BorderLayout.NORTH); exp.add(expID, BorderLayout.CENTER); annotationHeaders.add("UniqueExpID"); currentAnnotations.put("UniqueExpID", exp); } /** * Method building the annotation menu. */ public void buildAnnotationsMenu() { newExpPanel.removeAll(); int x = 0; int y = 0; gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(5, 10, 5, 30); gbc.gridx = x; gbc.gridy = y; newExpPanel.add(currentAnnotations.get("UniqueExpID"), gbc); x++; for (String s : currentAnnotations.keySet()) { if (!s.equals("UniqueExpID")) { if (x > 6) { x = 0; y++; } gbc.gridx = x; gbc.gridy = y; newExpPanel.add(currentAnnotations.get(s), gbc); x++; } } newExpPanel.repaint(); newExpPanel.revalidate(); setNewOrExistingView(); repaintSelectedFiles(); } // Combined two javadocs /** * Creates an uploadFileRow from the provided files. Checks if the files are * already in an uploadFileRow so there won't be duplicates. Displays an * error message if it was selected and added previously. * * @param files * The files to make an uploadFileRow out of */ public void createUploadFileRow(File[] files) { for (File f : files) { if (!uploadFileRows.containsKey(f)) { UploadFileRow fileRow = new UploadFileRow(f, this, isNewExp); uploadFileRows.put(f, fileRow); } else { JOptionPane.showMessageDialog(this, "File already selected: " + f.getName() + "", "File error", JOptionPane.ERROR_MESSAGE); } } repaintSelectedFiles(); } /** * Deletes an uploadFileRow and calls repaintSelectedFiles() to repaint. If * it fails to find the file, an error message is shown to the user.<br> * OR<br> * Deletes a file row. * * @param f * This is used to identify which uploadFileRow to be deleted.<br> * OR<br> * Used to identify which fileRow to be deleted. */ public void deleteFileRow(File f) { if (uploadFileRows.containsKey(f)) { uploadFileRows.remove(f); uploadFilesPanel.removeAll(); buttonsPanel.removeAll(); repaintSelectedFiles(); } else { JOptionPane.showMessageDialog(this, "Can't delete file: " + f.getName() + "", "File error", JOptionPane.ERROR_MESSAGE); } } private void clear() { uploadFileRows = new HashMap<File, UploadFileRow>(); annotationBoxes = new HashMap<String, JComboBox<String>>(); annotationFields = new HashMap<String, JTextField>(); annotationHeaders = new ArrayList<String>(); expID.setText(""); } /** * Checks if there are any uploadfilerows. Disables the uploadbutton if * there aren't, and adds them to the panel if there are. After these * updates, it repaints the panel. */ private void repaintSelectedFiles() { uploadFilesPanel.add(boldTextLabel); if (!uploadFileRows.isEmpty()) { for (File f : uploadFileRows.keySet()) { uploadFilesPanel.add(uploadFileRows.get(f)); } } else { enableUploadButton(false); } buttonsPanel.add(selectButton); buttonsPanel.add(uploadSelectedBtn); buttonsPanel.add(uploadButton); uploadFilesPanel.add(buttonsPanel); repaint(); revalidate(); } /** * Method that modifies the view depending on new or existing experiment */ private void setNewOrExistingView() { if (isNewExp) { expID.setEnabled(true); selectButton.setText("Browse files"); uploadSelectedBtn.setVisible(true); uploadSelectedBtn.setText("Create with selected files"); uploadButton.setText("Create with all files"); } else { uploadSelectedBtn.setVisible(false); selectButton.setText("Add files"); } } /** * Method returning the ExpID for a new experiment. * * @return the ID of a experiment. */ public String getNewExpID() { return expID.getText(); } /** * Method returning the genome chosen for the file given. * * @param f * The file suppose to be uploaded. * @return a String representing the chosen genome version. */ public String getGenomeVersion(File f) { if (uploadFileRows.containsKey(f)) { return uploadFileRows.get(f).getGenomeRelease(); } return null; } /** * Method returning the chosen annotations for the new experiment. * * @return an AnnotationDataValue array with all the annotations. */ public AnnotationDataValue[] getUploadAnnotations() { AnnotationDataValue[] a = new AnnotationDataValue[annotationHeaders .size() - 1]; int nrOfAdded = 0; for (int i = 0; i < annotationHeaders.size(); i++) { String annotationName = annotationHeaders.get(i); if (!annotationName.equals("UniqueExpID")) { String value = getEnteredAnnotationValue(annotationName); a[nrOfAdded] = new AnnotationDataValue(Integer.toString(i), annotationName, value); nrOfAdded++; } } return a; } /** * Method getting the files to be uploaded. * * @return an array with the files. */ public ArrayList<File> getUploadFiles() { ArrayList<File> files = new ArrayList<>(); for (File f : uploadFileRows.keySet()) { files.add(f); } return files; } /** * Method returning the files that are selected. * * @return an ArrayList with the selected files. */ public ArrayList<File> getSelectedFilesToUpload() { ArrayList<File> files = new ArrayList<>(); for (File f : uploadFileRows.keySet()) { if (uploadFileRows.get(f).isSelected()) { files.add(f); } } return files; } /** * Method returning the type of the files to be uploaded. * * @return a HashMap with the filenames and there types. */ public HashMap<String, String> getTypes() { HashMap<String, String> types = new HashMap<>(); for (File f : uploadFileRows.keySet()) { types.put(f.getName(), uploadFileRows.get(f).getType()); } return types; } /** * Method checking if the forced annotations are filled. * * @return true if all forced annotation fields (including expID) are * filled. Otherwise returns false. */ public boolean forcedAnnotationCheck() { String expIDName = expID.getText(); if (expIDName == null || expIDName.equals("")) { return false; } boolean allForcedAnnotationsAreFilled = true; String annotationName; String text; JTextField annotationField; JComboBox<String> annotationBox; for (int i = 0; i < annotations.length; i++) { if (annotations[i].isForced()) { annotationName = annotations[i].getName(); if (annotationFields.containsKey(annotationName)) { annotationField = annotationFields.get(annotationName); text = annotationField.getText(); if (text == null || text.equals("")) { allForcedAnnotationsAreFilled = false; } text = null; } else if (annotationBoxes.containsKey(annotationName)) { annotationBox = annotationBoxes.get(annotationName); text = (String) annotationBox.getSelectedItem(); if (text == null || text.equals("")) { allForcedAnnotationsAreFilled = false; } text = null; } } } return allForcedAnnotationsAreFilled; } // one javadoc from interface, one from here. /** * Sets the experiment button to either be enabled or disabled. Only enables * it if there are selected files and all forced annotations fields are * filled.<br> * OR<br> * Calls the uploadPanel's enableUploadButton method to try to either make * the upload button enabled or disabled. If all of the required annotation * fields are NOT filled, this method won't set it to true. * * @param b * Whether it should try to: enable the button (true) or disable * it (false)<br> * OR<br> * Whether it should try to make the button enabled (true) or * disabled (false). */ public void enableUploadButton(boolean b) { if (b) { if (isNewExp) { if (!uploadFileRows.isEmpty() && forcedAnnotationCheck()) { uploadSelectedBtn.setEnabled(true); uploadButton.setEnabled(true); } } else { if (!uploadFileRows.isEmpty()) { uploadButton.setText("Save & Upload"); uploadButton.setEnabled(true); } } } else { uploadSelectedBtn.setEnabled(false); if (isNewExp) { uploadButton.setEnabled(false); } else { uploadButton.setText("Save changes"); uploadButton.setEnabled(true); } } } public void setSelectButtonEnabled(boolean enabled) { selectButton.setEnabled(enabled); } /** * Listener for when the text in a textfield changes. */ private class FreetextListener implements DocumentListener { @Override public void insertUpdate(DocumentEvent documentEvent) { react(documentEvent); } @Override public void removeUpdate(DocumentEvent documentEvent) { react(documentEvent); } @Override public void changedUpdate(DocumentEvent documentEvent) { react(documentEvent); } public void react(DocumentEvent documentEvent) { if (forcedAnnotationCheck()) { enableUploadButton(true); } else { enableUploadButton(false); } } } /** * c12jhn 16/4-15 Getter to get all of the annotationfields of the panel. * Used only in testing * * @return */ public HashMap<String, JTextField> getAnnotationFields() { return this.annotationFields; } /** * Method that filles out the annotations fields with an existing * experiments values. Used to edit an existing experiment. * * @param ed * - Experiment to get annotations from */ public void setExistingExp(ExperimentData ed) { expID.setText(ed.getName()); for (AnnotationDataValue data : ed.getAnnotations()) { if (annotationBoxes.containsKey(data.getName())) { annotationBoxes.get(data.getName()).setSelectedItem( data.getValue()); } else if (annotationFields.containsKey(data.getName())) { annotationFields.get(data.getName()).setText(data.getValue()); } } expID.setEnabled(false); } /** * Returns the status if active experiment is a new experiment or existing * * @return */ public boolean getIsNewExp() { return isNewExp; } }