package medsavant.discovery; import com.healthmarketscience.sqlbuilder.BinaryCondition; import com.healthmarketscience.sqlbuilder.ComboCondition; import com.healthmarketscience.sqlbuilder.Condition; import com.jidesoft.pane.CollapsiblePane; import com.jidesoft.swing.ButtonStyle; import com.jidesoft.swing.JideButton; import jannovar.common.VariantType; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.math.BigDecimal; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.ScrollPaneConstants; import medsavant.discovery.localDB.DiscoveryDBFunctions; import net.miginfocom.swing.MigLayout; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.ut.biolab.medsavant.MedSavantClient; import org.ut.biolab.medsavant.client.view.login.LoginController; import org.ut.biolab.medsavant.client.project.ProjectController; import org.ut.biolab.medsavant.client.reference.ReferenceController; import org.ut.biolab.medsavant.client.util.ClientMiscUtils; import org.ut.biolab.medsavant.client.util.MedSavantWorker; import org.ut.biolab.medsavant.client.view.component.ProgressWheel; import org.ut.biolab.medsavant.client.view.genetics.variantinfo.ClinvarSubInspector; import org.ut.biolab.medsavant.client.view.genetics.variantinfo.HGMDSubInspector; import org.ut.biolab.medsavant.client.view.genetics.variantinfo.SimpleVariant; import org.ut.biolab.medsavant.shared.appdevapi.DBAnnotationColumns; import org.ut.biolab.medsavant.shared.db.TableSchema; import org.ut.biolab.medsavant.shared.format.BasicVariantColumns; import org.ut.biolab.medsavant.shared.format.CustomField; import org.ut.biolab.medsavant.shared.serverapi.AnnotationManagerAdapter; import org.ut.biolab.medsavant.shared.serverapi.VariantManagerAdapter; /** * A summary panel containing detailed information for a variant. * Information includes gene name, mutation type, allele frequency, * as well as Clinvar and HGMD annotations with URLs to external resources. * * @author rammar */ public class VariantSummaryPanel extends JScrollPane { private static final int DB_VARIANT_REQUEST_LIMIT= 5000; private static final Log LOG = LogFactory.getLog(MedSavantClient.class); private static final String baseDBSNPUrl= "http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?searchType=adhoc_search&rs="; private static final String baseClinvarUrl= "http://www.ncbi.nlm.nih.gov/clinvar/"; private static final String baseOMIMUrl= "http://www.omim.org/entry/"; private static final String basePubmedUrl= "http://www.ncbi.nlm.nih.gov/pubmed/"; private static final Color WARNING_ORANGE= new Color(249, 114, 85); // other option: (242, 103, 34); private static final String POLYPHEN2HUMVAR_COLUMN= DBAnnotationColumns.POLYPHEN2HUMVAR; private static final String SIFT_COLUMN= DBAnnotationColumns.SIFT; private static final String PHYLOP_COLUMN= DBAnnotationColumns.PHYLOP; private static final List<String> predictorColumns= Arrays.asList( POLYPHEN2HUMVAR_COLUMN, SIFT_COLUMN,PHYLOP_COLUMN ); // for now these are hard-coded, but this may be updated later private static final double POLYPHEN2HUMVAR_PROBABLY_DAMAGING_THRESHOLD= 0.90; // above this private static final double POLYPHEN2HUMVAR_POSSIBLY_DAMAGING_THRESHOLD= 0.80; // above this private static final double SIFT_PROBABLY_DAMAGING_THRESHOLD= 0.05; // below this private static final String PROBABLY_DAMAGING= "probably damaging"; private static final String POSSIBLY_DAMAGING= "possibly damaging"; /* LOF mutations to colour as red, potentially harmful mutations to colour * as orange. */ private static final List<String> RED_MUTATIONS= Arrays.asList( VariantType.FS_DELETION.toString(), VariantType.FS_DUPLICATION.toString(), VariantType.FS_INSERTION.toString(), VariantType.FS_SUBSTITUTION.toString(), VariantType.STOPGAIN.toString(), VariantType.SPLICING.toString(), VariantType.ERROR.toString() // Errors are red as well, but aren't functional annotations ); private static final List<String> ORANGE_MUTATIONS= Arrays.asList( VariantType.MISSENSE.toString(), VariantType.NON_FS_DELETION.toString(), VariantType.NON_FS_DUPLICATION.toString(), VariantType.NON_FS_INSERTION.toString(), VariantType.NON_FS_SUBSTITUTION.toString(), VariantType.START_LOSS.toString() ); private TableSchema ts= ProjectController.getInstance().getCurrentVariantTableSchema(); private VariantManagerAdapter vma= MedSavantClient.VariantManager; public JPanel summaryPanel= new JPanel(); private int PANE_WIDTH= 380; private int PANE_WIDTH_OFFSET= 20; private int PANE_HEIGHT= 20; // minimum, but it'll stretch down - may need to change later private String currentGeneSymbol; private JLabel titleLabel; private String cgdPaneTitle= "Clinical Genomics Database (CGD) details"; private String clinvarPaneTitle= "Clinvar details"; private String hgmdPaneTitle= "HGMD details"; private String otherIndividualsPaneTitle= "Individuals with this variant"; private MedSavantWorker otherIndividualsThread; private JPanel variantPanel; private List<String> alleleFrequencyColumns; private String afPaneTitle= "Allele frequency details"; private String predictorPaneTitle= "Variant harmfulness prediction"; private List<JComponent> clearList= new LinkedList<JComponent>(); //variant properties private String chromosome; private int start; private int end; private String reference; private String alternate; private String zygosity; private List<String> mutationEffects; private List<String> mutationAnnotations; /** * Create a new scrollable VariantSummaryPanel. * @param title The title of this panel */ public VariantSummaryPanel(String title) { this.setBorder(BorderFactory.createEmptyBorder()); this.setViewportView(summaryPanel); this.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); this.variantPanel= new JPanel(); summaryPanel.setLayout(new MigLayout("gapy 0px")); variantPanel.setLayout(new MigLayout()); //summaryPanel.setBackground(ViewUtil.getSidebarColor()); titleLabel= new JLabel(title); titleLabel.setFont(new Font(titleLabel.getFont().getName(), Font.BOLD, 20)); summaryPanel.add(titleLabel, "alignx center, span"); summaryPanel.add(variantPanel, "alignx center, span"); summaryPanel.add(new JLabel(" "), "wrap"); // spacer this.autoSize(PANE_WIDTH, PANE_HEIGHT, PANE_WIDTH_OFFSET); this.alleleFrequencyColumns= getAlleleFrequencyColumns(); } /** * Update the title for the VariantSummaryPanel. * @param geneSymbol The new title string */ public void updateGeneSymbol(String geneSymbol) { titleLabel.setText(geneSymbol); currentGeneSymbol= geneSymbol; summaryPanel.revalidate(); } /** * Add or update the annotation for this variant. * @param row The entire row entry from the DB for this variant. * @param header The table header row */ public void updateAnnotation(Object[] row, List<String> header) { /* Parse the information. */ this.chromosome= (String) row[BasicVariantColumns.INDEX_OF_CHROM]; this.start= ((Integer) row[BasicVariantColumns.INDEX_OF_START_POSITION]).intValue(); this.end= ((Integer) row[BasicVariantColumns.INDEX_OF_END_POSITION]).intValue(); this.reference= (String) row[BasicVariantColumns.INDEX_OF_REF]; this.alternate= (String) row[BasicVariantColumns.INDEX_OF_ALT]; this.zygosity= (String) row[BasicVariantColumns.INDEX_OF_ZYGOSITY]; // mutation details can be comma-delimited lists String effects= (String) row[header.indexOf( BasicVariantColumns.JANNOVAR_EFFECT.getAlias())]; String annotations= (String) row[header.indexOf( BasicVariantColumns.JANNOVAR_SYMBOL.getAlias())]; this.mutationEffects= Arrays.asList(effects.split(",")); this.mutationAnnotations= Arrays.asList(annotations.split(",")); /* Clean up old components then add these details to the variant panel. */ variantPanel.removeAll(); variantPanel.add(getBoldLabel(chromosome + ": " + start + "-" + end), "span"); variantPanel.add(getBoldLabel("Reference")); variantPanel.add(new JLabel(reference), "split 2, wrap"); variantPanel.add(getBoldLabel("Alternate")); variantPanel.add(new JLabel(alternate), "split 2, wrap"); variantPanel.add(getBoldLabel("Zygosity")); variantPanel.add(new JLabel(zygosity), "split 2, wrap"); // try-catch block in case mutationEffects and mutationAnnotations are // not the same size try { for (int i= 0; i != mutationEffects.size(); ++i) { String currentEffect= mutationEffects.get(i); String currentAnnotation= mutationAnnotations.get(i); Color mutationColor= Color.DARK_GRAY; // default colour if (RED_MUTATIONS.contains(currentEffect)) { mutationColor= Color.RED; } else if (ORANGE_MUTATIONS.contains(currentEffect)) { mutationColor= WARNING_ORANGE; } variantPanel.add(getColorTextArea(currentEffect + ": " + currentAnnotation, mutationColor), "span"); } } catch (Exception ex) { //DialogUtils.displayError(ex.getMessage()); ex.printStackTrace(); } variantPanel.revalidate(); // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add or update the allele frequency pane for this variant. * @param row The entire row entry from the DB for this variant. * @param header The table header row */ public void updateAlleleFrequencyPane(Object[] row, List<String> header) { CollapsiblePane afPane= getCollapsiblePane(afPaneTitle); for (String afColumn : alleleFrequencyColumns) { String afValue= "N/A"; if ((BigDecimal) row[header.indexOf(afColumn)] != null) afValue= ((BigDecimal) row[header.indexOf(afColumn)]).toString(); afPane.add(getBoldLabel(afColumn)); afPane.add(new JLabel(afValue), "wrap"); } summaryPanel.add(afPane, "wrap"); // add to list of components clearList.add(afPane); // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add or update the harmfulness predictors pane for this variant. * @param row The entire row entry from the DB for this variant. * @param header The table header row */ public void updateHarmfulnessPredictorsPane(Object[] row, List<String> header) { CollapsiblePane predictorPane= getCollapsiblePane(predictorPaneTitle); for (String predictorColumn : predictorColumns) { String predictorValue= "N/A"; JLabel predictorJLabel= getColorLabel(predictorValue, Color.DARK_GRAY); /* Check if there is a value and then evaluate it before outputting. */ if ((BigDecimal) row[header.indexOf(predictorColumn)] != null) { predictorValue= ((BigDecimal) row[header.indexOf(predictorColumn)]).toString(); predictorJLabel= getColorLabel(predictorValue, Color.DARK_GRAY); /* Classify the variants. * SIFT < 0.05 => probably damaging * Polyphen2 >= 0.90 => probably damaging * 0.90 > Polyphen2 >= 0.80 => probably damanging */ if (predictorColumn.equals(SIFT_COLUMN) && Double.parseDouble(predictorValue) < SIFT_PROBABLY_DAMAGING_THRESHOLD) { predictorJLabel= getColorLabel(predictorValue + " " + PROBABLY_DAMAGING, Color.RED); } else if (predictorColumn.equals(POLYPHEN2HUMVAR_COLUMN) && Double.parseDouble(predictorValue) >= POLYPHEN2HUMVAR_PROBABLY_DAMAGING_THRESHOLD) { predictorJLabel= getColorLabel(predictorValue + " " + PROBABLY_DAMAGING, Color.RED); } else if (predictorColumn.equals(POLYPHEN2HUMVAR_COLUMN) && Double.parseDouble(predictorValue) >= POLYPHEN2HUMVAR_POSSIBLY_DAMAGING_THRESHOLD) { predictorJLabel= getColorLabel(predictorValue + " " + POSSIBLY_DAMAGING, WARNING_ORANGE); } } predictorPane.add(getBoldLabel(predictorColumn)); predictorPane.add(predictorJLabel, "wrap"); } summaryPanel.add(predictorPane, "wrap"); // add to list of components clearList.add(predictorPane); // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add or update the clinvar pane. * @param csi The ClinvarSubInspector */ public void updateClinvarPane(ClinvarSubInspector csi) { CollapsiblePane clinvarPane= getCollapsiblePane(clinvarPaneTitle); String disease= csi.getDisease(); // Convert all "_" to spaces, "|" to "; " and "\x2c" to "," disease= disease.replaceAll("_", " "); disease= disease.replaceAll("\\|", "; "); disease= disease.replaceAll("\\\\x2c", ","); JTextArea diseaseText= new JTextArea(disease); diseaseText.setLineWrap(true); diseaseText.setWrapStyleWord(true); // wrap after words, so as not to break words up diseaseText.setMinimumSize(new Dimension(PANE_WIDTH / 2, diseaseText.getPreferredSize().height)); diseaseText.setBackground(summaryPanel.getBackground()); // Process the omim allelic variant text for URL String omimAllelicVariantID_url= csi.getOmimAllelicVariantID().replaceAll("\\.", "#"); // Process the Clinvar accession text (get the root) for URL Matcher m= Pattern.compile("([^\\.]+)\\.").matcher(csi.getClinvarAccession()); String accessionRoot= ""; if (m.find()) accessionRoot= m.group(1); /* Collapse the pane if the Clinvar entry is empty. Treat it as empty * if both dbSNP AND clinvar accession are empty. */ if (!(csi.getRsID().equals("") && csi.getClinvarAccession().equals(""))) { // Add labels and buttons to the pane clinvarPane.add(getBoldLabel("Disease")); clinvarPane.add(diseaseText, "wrap"); clinvarPane.add(getBoldLabel("dbSNP ID")); clinvarPane.add(getURLButton(csi.getRsID(), baseDBSNPUrl, csi.getRsID(), true), "wrap"); clinvarPane.add(getBoldLabel("OMIM")); clinvarPane.add(getURLButton(csi.getOmimID(), baseOMIMUrl, csi.getOmimID(), true), "wrap"); clinvarPane.add(getBoldLabel("OMIM Allelic Variant")); clinvarPane.add(getURLButton(csi.getOmimAllelicVariantID(), baseOMIMUrl, omimAllelicVariantID_url, false), "wrap"); clinvarPane.add(getBoldLabel("Clinvar accession")); clinvarPane.add(getURLButton(csi.getClinvarAccession(), baseClinvarUrl, accessionRoot, true), "wrap"); clinvarPane.add(getBoldLabel("Clinical significance")); clinvarPane.add(new JLabel(csi.getClnSig()), "wrap"); summaryPanel.add(clinvarPane, "wrap"); // add to list of components clearList.add(clinvarPane); } // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add or update the HGMD pane. * @param hsi The HGMDSubInspector */ public void updateHGMDPane(HGMDSubInspector hsi) { CollapsiblePane hgmdPane= getCollapsiblePane(hgmdPaneTitle); // use JTextAreas when text runs over one line JTextArea diseaseText= new JTextArea(hsi.getDisease()); diseaseText.setLineWrap(true); diseaseText.setWrapStyleWord(true); // wrap after words, so as not to break words up diseaseText.setMinimumSize(new Dimension(PANE_WIDTH / 2, diseaseText.getPreferredSize().height)); diseaseText.setBackground(summaryPanel.getBackground()); JTextArea commentsText= new JTextArea(hsi.getHGMDComments()); commentsText.setLineWrap(true); commentsText.setWrapStyleWord(true); // wrap after words, so as not to break words up commentsText.setMinimumSize(new Dimension(PANE_WIDTH / 2, commentsText.getPreferredSize().height)); commentsText.setBackground(summaryPanel.getBackground()); /* Don't add the pane if the HGMD entry is empty. Treat it as empty * if both disease AND omimid are empty. */ if (!(hsi.getDisease().equals("") && hsi.getOmimID().equals(""))) { // Add labels and buttons to the pane hgmdPane.add(getBoldLabel("Disease")); hgmdPane.add(diseaseText, "wrap"); hgmdPane.add(getBoldLabel("OMIM")); hgmdPane.add(getURLButton(hsi.getOmimID(), baseOMIMUrl, hsi.getOmimID(), true), "wrap"); hgmdPane.add(getBoldLabel("Pubmed")); hgmdPane.add(getURLButton(hsi.getPubmedID(), basePubmedUrl, hsi.getPubmedID(), true), "wrap"); hgmdPane.add(getBoldLabel("HGMD comments")); hgmdPane.add(commentsText); summaryPanel.add(hgmdPane, "wrap"); // add to list of components clearList.add(hgmdPane); } // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add of update the CGD pane. * @param zygosity String for zygosity * @param gender String for gender * @param classification Classification as determined by another program (required to deal with compound hets). */ public void updateCGDPane(String zygosity, String gender, String classification){ CollapsiblePane cgdPane= getCollapsiblePane(cgdPaneTitle); /* Get the CGD annotation. */ List<String> variantClassification= DiscoveryDBFunctions.getClassification(currentGeneSymbol, zygosity, "", gender); String inheritance= variantClassification.get(1); String disease= DiscoveryDBFunctions.getDisease(currentGeneSymbol); /* If there is no CGD annotation, collapse the pane. */ if (classification != null) { cgdPane.add(getBoldLabel("Classification")); cgdPane.add(new JLabel(classification), "wrap"); cgdPane.add(getBoldLabel("Inheritance")); cgdPane.add(new JLabel(inheritance), "wrap"); cgdPane.add(getBoldLabel("Disease")); JTextArea diseaseText= new JTextArea(disease); diseaseText.setLineWrap(true); diseaseText.setWrapStyleWord(true); // wrap after words, so as not to break words up diseaseText.setMinimumSize(new Dimension(PANE_WIDTH / 2, diseaseText.getPreferredSize().height)); diseaseText.setBackground(summaryPanel.getBackground()); cgdPane.add(diseaseText, "wrap"); summaryPanel.add(cgdPane, "wrap"); // add to list of components clearList.add(cgdPane); } // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Add or update the other individuals pane to show all DNA IDs with this variant. * @param simpleVar The SimpleVariant object representing this variant. */ public void updateOtherIndividualsPane(final SimpleVariant simpleVar) { final CollapsiblePane otherIndividualsPane= getCollapsiblePane(otherIndividualsPaneTitle); summaryPanel.add(otherIndividualsPane, "wrap"); // add to list of components clearList.add(otherIndividualsPane); final ProgressWheel pw= new ProgressWheel(); pw.setIndeterminate(true); otherIndividualsPane.add(pw, "alignx center"); //otherIndividualsPane.updateUI(); // causes random NullPointerExceptions; use revalidate() instead otherIndividualsPane.revalidate(); /* Get the other individuals DNA IDs. */ // add a random number to differentiate the threads by pagename otherIndividualsThread= new MedSavantWorker<Void>("updateOtherIndividualsPane" + Double.toString(Math.random())) { @Override protected void showSuccess(Void result) { } @Override protected Void doInBackground() throws Exception { JPanel dnaIDPanel; List<String> dnaIDList= getAllDNAIDsForVariant(simpleVar); Collections.sort(dnaIDList); // sort the DNA IDs so that a user can scroll through quickly int totalDBPatients= 0; try { totalDBPatients= MedSavantClient.PatientManager.getPatients( LoginController.getInstance().getSessionID(), ProjectController.getInstance().getCurrentProjectID()).size(); } catch (Exception e) { LOG.error("Error processing total patient counter. " + e.toString()); e.printStackTrace(); } /* Update the other individuals pane. */ dnaIDPanel= new JPanel(new MigLayout("alignx center, insets 0px")); otherIndividualsPane.remove(pw); String individuals= " individual "; if (dnaIDList.size() > 1) individuals= " individuals "; otherIndividualsPane.setTitle(dnaIDList.size() + individuals + "with this variant (" + totalDBPatients + " individuals in database)"); for (String dnaID : dnaIDList) { dnaIDPanel.add(new JLabel(dnaID), "wrap"); } /* Collapse the pane because it takes up a lot of space. The * pane title should be informative enough to start. */ otherIndividualsPane.collapse(true); otherIndividualsPane.add(dnaIDPanel); otherIndividualsPane.revalidate(); return null; } }; otherIndividualsThread.execute(); //summaryPanel.revalidate(); // deal with some weird redrawing error when the collapsiblepane shrinks from previous size summaryPanel.updateUI(); } /** * Get a list of DNA IDs that have this variant. * @param simpleVar The SimpleVariant object representing this variant. * @return A list of DNA IDs (as strings) that have this variant. */ private List<String> getAllDNAIDsForVariant(SimpleVariant simpleVar) { List<String> allDNAIDs= new LinkedList<String>(); /* Create the ComboCondition to identify all individuals with this variant. */ ComboCondition cc= new ComboCondition(ComboCondition.Op.AND); cc.addCondition(BinaryCondition.equalTo(ts.getDBColumn(BasicVariantColumns.CHROM), simpleVar.getChromosome())); cc.addCondition(BinaryCondition.equalTo(ts.getDBColumn(BasicVariantColumns.START_POSITION), simpleVar.getStartPosition())); cc.addCondition(BinaryCondition.equalTo(ts.getDBColumn(BasicVariantColumns.END_POSITION), simpleVar.getEndPosition())); cc.addCondition(BinaryCondition.equalTo(ts.getDBColumn(BasicVariantColumns.REF), simpleVar.getReference())); cc.addCondition(BinaryCondition.equalTo(ts.getDBColumn(BasicVariantColumns.ALT), simpleVar.getAlternate())); Condition[][] conditionMatrix= new Condition[1][1]; conditionMatrix[0][0]= cc; /* Get variants in chunks based on a request limit offset to save memory. */ List<Object[]> allVariants= new ArrayList<Object[]>(DB_VARIANT_REQUEST_LIMIT); try { int fetchPosition= 0; List<Object[]> currentVariants= null; while (currentVariants == null || currentVariants.size() != 0 ){ currentVariants= vma.getVariants(LoginController.getInstance().getSessionID(), ProjectController.getInstance().getCurrentProjectID(), ReferenceController.getInstance().getCurrentReferenceID(), conditionMatrix, fetchPosition, DB_VARIANT_REQUEST_LIMIT); fetchPosition += DB_VARIANT_REQUEST_LIMIT; allVariants.addAll(currentVariants); } } catch (Exception e) { LOG.error("Error processing query. " + e.toString()); e.printStackTrace(); } for (Object[] row : allVariants) { allDNAIDs.add((String) row[BasicVariantColumns.INDEX_OF_DNA_ID]); } return allDNAIDs; } /** * Lets the scrollable component autosize itself optimally for the screen. * @param width * @param height * @param offset */ public void autoSize(int width, int height, int offset) { PANE_WIDTH= width; PANE_HEIGHT= height; PANE_WIDTH_OFFSET= offset; summaryPanel.setMinimumSize(new Dimension(width, height)); this.setMinimumSize(new Dimension(summaryPanel.getMinimumSize().width + offset, height)); this.setPreferredSize(new Dimension(summaryPanel.getMinimumSize().width, summaryPanel.getMaximumSize().height)); } /** * Get a new CollapsiblePane with the preferred presets. * @param title Title of the pane */ private CollapsiblePane getCollapsiblePane(String title) { CollapsiblePane p= new CollapsiblePane(title); p.setLayout(new MigLayout("alignx center")); p.setStyle(CollapsiblePane.PLAIN_STYLE); p.setFocusPainted(false); p.collapse(false); // expand the collapsible pane p.setMinimumSize(new Dimension(PANE_WIDTH - PANE_WIDTH_OFFSET, 0)); return p; } /** * Create a bold label with the specified text * @param labelText The JLabel text */ private JLabel getBoldLabel(String labelText) { JLabel boldLabel= new JLabel(labelText); boldLabel.setFont(new Font(boldLabel.getFont().getName(), Font.BOLD, boldLabel.getFont().getSize())); return boldLabel; } /** * Create a bold coloured label with the specified text * @param labelText The JLabel text * @param c The text color */ private JLabel getColorLabel(String labelText, Color c) { JLabel colorLabel= getBoldLabel(labelText); colorLabel.setForeground(c); return colorLabel; } /** * Creates a coloured text area (to wrap lines) with the specified text. * @param text The text * @param c The text color */ private JTextArea getColorTextArea(String text, Color c) { JTextArea colorText= new JTextArea(text); colorText.setLineWrap(true); colorText.setWrapStyleWord(true); // wrap after words, so as not to break words up colorText.setMinimumSize(new Dimension(PANE_WIDTH - PANE_WIDTH/4, colorText.getPreferredSize().height)); colorText.setBackground(summaryPanel.getBackground()); colorText.setForeground(c); colorText.setFont(new Font(colorText.getFont().getName(), Font.BOLD, colorText.getFont().getSize() + 1)); // add 1 to the font size return colorText; } /** * Create a button that opens a URL in a web browser when clicked. * @param buttonText Button text * @param baseURL URL linked from the button * @param appendToURL Append text to the URL * @param doEncode encode the text using the UTF-8 * @return a JideButton that opens the URL in a web browser */ private JideButton getURLButton(String buttonText, final String baseURL, final String appendToURL, final boolean doEncode) { final String URL_CHARSET = "UTF-8"; JideButton urlButton= new JideButton(buttonText); urlButton.setButtonStyle(ButtonStyle.HYPERLINK_STYLE); urlButton.setForeground(Color.BLUE); urlButton.setToolTipText("Lookup " + buttonText + " on the web"); urlButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { try { URL url; if (doEncode) url = new URL(baseURL + URLEncoder.encode(appendToURL, URL_CHARSET)); else url = new URL(baseURL + appendToURL); java.awt.Desktop.getDesktop().browse(url.toURI()); } catch (Exception ex) { ClientMiscUtils.reportError("Problem launching website: %s", ex); } } }); return urlButton; } /** * Adds a custom panel to the summary panel. * @param custom Title of custom pane * @return The new custom CollapsiblePane to be modified. */ public CollapsiblePane addCustomAnnotation(String custom) { CollapsiblePane customPane= getCollapsiblePane(custom); summaryPanel.add(customPane, "wrap"); // add to list of components clearList.add(customPane); return customPane; } /** * Get the parent summary panel for the VariantSummaryPanel. * @return The summary panel */ public JPanel getSummaryPanel() { return summaryPanel; } /** * Get the Allele Frequency annotation columns from this database. * @return a list of the allele frequency column names. */ private List<String> getAlleleFrequencyColumns() { List<String> output= new ArrayList<String>(); try { AnnotationManagerAdapter am= MedSavantClient.AnnotationManagerAdapter; Map<String, Set<CustomField>> fieldMap= am.getAnnotationFieldsByTag(LoginController.getInstance().getSessionID(), true); Set<CustomField> columnNames= fieldMap.get(CustomField.ALLELE_FREQUENCY_TAG); for (CustomField cf : columnNames) { output.add(cf.getAlias()); } } catch (Exception e) { LOG.error("[" + this.getClass().getSimpleName() + "]: Error retrieving allele frequency columns."); e.printStackTrace(); } return output; } /** * Remove all components from main pane. */ public void clearSummaryPane() { for (JComponent jc : clearList) { if (jc != null) summaryPanel.remove(jc); } // Ensure the list is empty clearList.clear(); // should be switched to removeAll() for Java 1.7 } }