/* * Copyright (C) 2014 University of Toronto, Computational Biology Lab. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package org.ut.biolab.medsavant.client.patient; import edu.toronto.cs.medsavant.medsavant.app.api.appcomm.AppCommHandler; import edu.toronto.cs.medsavant.medsavant.app.api.appcomm.AppCommRegistry; import edu.toronto.cs.medsavant.medsavant.app.api.appcomm.BAMFileComm; import edu.toronto.cs.medsavant.medsavant.app.api.appcomm.PatientVariantAnalyzeComm; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Image; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.MalformedURLException; import java.net.URL; import java.rmi.RemoteException; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Set; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import net.miginfocom.swing.MigLayout; import org.ut.biolab.medsavant.MedSavantClient; import org.ut.biolab.medsavant.client.user.UserController; import org.ut.biolab.medsavant.client.view.login.LoginController; import org.ut.biolab.medsavant.client.patient.pedigree.PedigreeCanvas; import org.ut.biolab.medsavant.client.project.ProjectController; import org.ut.biolab.medsavant.client.util.ClientMiscUtils; import org.ut.biolab.medsavant.client.util.MedSavantExceptionHandler; import org.ut.biolab.medsavant.client.view.MedSavantFrame; import org.ut.biolab.medsavant.client.view.component.KeyValuePairPanel; import org.ut.biolab.medsavant.client.view.dialog.ComboForm; import org.ut.biolab.medsavant.client.view.util.StandardFixableWidthAppPanel; import org.ut.biolab.medsavant.client.view.util.ViewUtil; import org.ut.biolab.medsavant.component.field.editable.EditableField; import org.ut.biolab.medsavant.component.field.editable.EnumEditableField; import org.ut.biolab.medsavant.component.field.editable.FieldCommittedListener; import org.ut.biolab.medsavant.component.field.editable.StringEditableField; import org.ut.biolab.medsavant.component.field.validator.URLValidator; import org.ut.biolab.medsavant.shared.model.Cohort; import org.ut.biolab.medsavant.shared.model.SessionExpiredException; import org.ut.biolab.medsavant.shared.model.UserLevel; /** * * @author mfiume */ public class PatientView extends JPanel implements FieldCommittedListener { private Patient patient; private KeyValuePairPanel profileKVP; private boolean isCurrentUserAdmin = false; // profile keys public static final String FATHER_ID = "Father ID"; public static final String MOTHER_ID = "Mother ID"; public static final String FAMILY_ID = "Family ID"; public static final String AFFECTED = "Affected"; public static final String HOSPITAL_ID = "Hospital ID"; public static final String SEX = "Sex"; // genetic keys public static final String DNA_ID = "DNA ID"; public static final String BAM_URL = "Read Alignment URL"; // phenotype keys public static final String PHENOTYPE = "HPO IDs"; private KeyValuePairPanel geneticsKVP; private KeyValuePairPanel phenotypeKVP; private StandardFixableWidthAppPanel content; private JPanel cohortListPanel; public PatientView() { initView(); } public PatientView(Patient patient) { initView(); setPatient(patient); } private void initView() { try { isCurrentUserAdmin = MedSavantClient.UserManager.getSessionUsersLevel(LoginController.getSessionID()) == UserLevel.ADMIN; } catch (Exception e) { e.printStackTrace(); } this.setLayout(new BorderLayout()); content = new StandardFixableWidthAppPanel(); this.add(content, BorderLayout.CENTER); initBlocks(); } private KeyValuePairPanel getKVP() { KeyValuePairPanel kvp = new KeyValuePairPanel(1, true); return kvp; } private void initBlocks() { JPanel subsectionBasicInfo = content.addBlock("Basic Information"); JPanel subsectionCohort = content.addBlock("Cohort(s)"); JPanel subsectionGenetics = content.addBlock("Genetics"); JPanel subsectionPhenotypes = content.addBlock("Phenotypes"); JButton addToCohortButton = ViewUtil.getSoftButton("Add to cohort..."); cohortListPanel = ViewUtil.getClearPanel(); addToCohortButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { Cohort[] cohorts = MedSavantClient.CohortManager.getCohorts(LoginController.getSessionID(), ProjectController.getInstance().getCurrentProjectID()); ComboForm form = new ComboForm(cohorts, "Select Cohort", "Select which cohort to add to:"); form.setVisible(true); Cohort selected = (Cohort) form.getSelectedValue(); if (selected == null) { return; } MedSavantClient.CohortManager.addPatientsToCohort(LoginController.getSessionID(), new int[]{patient.getID()}, selected.getId()); PatientView.this.refreshView(); } catch (Exception ex) { ClientMiscUtils.reportError("Error adding individuals to cohort: %s", ex); } } }); subsectionCohort.setLayout(new MigLayout("insets 0")); subsectionCohort.add(cohortListPanel, "wrap"); if (isCurrentUserAdmin) { subsectionCohort.add(addToCohortButton); } profileKVP = getKVP(); profileKVP.addKeyWithValue(HOSPITAL_ID, ""); profileKVP.addKeyWithValue(SEX, ""); profileKVP.addKeyWithValue(AFFECTED, ""); profileKVP.addKeyWithValue(FAMILY_ID, ""); profileKVP.addKeyWithValue(MOTHER_ID, ""); profileKVP.addKeyWithValue(FATHER_ID, ""); subsectionBasicInfo.add(profileKVP); geneticsKVP = getKVP(); geneticsKVP.addKeyWithValue(DNA_ID, ""); geneticsKVP.addKeyWithValue(BAM_URL, ""); subsectionGenetics.add(geneticsKVP); phenotypeKVP = getKVP(); phenotypeKVP.addKeyWithValue(PHENOTYPE, ""); subsectionPhenotypes.add(phenotypeKVP); } void setPatient(Patient patient) { this.patient = patient; refreshView(); } private void refreshView() { content.setTitle(patient.getHospitalID()); StringEditableField individualIDField = new StringEditableField(); individualIDField.setTag(HOSPITAL_ID); individualIDField.setValue(patient.getHospitalID()); individualIDField.addFieldComittedListener(this); EnumEditableField sexField = new EnumEditableField(new String[]{"Undesignated", "Male", "Female"}); sexField.setValue(patient.getSex()); sexField.setTag(SEX); sexField.addFieldComittedListener(this); EnumEditableField affectedField = new EnumEditableField(new String[]{"Yes", "No"}); affectedField.setValue(patient.isAffected() ? "Yes" : "No"); affectedField.setTag(AFFECTED); affectedField.addFieldComittedListener(this); EditablePatientField motherField = new EditablePatientField(true); motherField.setValue(patient.getMotherHospitalID()); motherField.setTag(MOTHER_ID); motherField.addFieldComittedListener(this); EditablePatientField fatherField = new EditablePatientField(true); fatherField.setValue(patient.getFatherHospitalID()); fatherField.setTag(FATHER_ID); fatherField.addFieldComittedListener(this); StringEditableField familyIDField = new StringEditableField(); familyIDField.setValue(patient.getFamilyID()); familyIDField.setTag(FAMILY_ID); familyIDField.addFieldComittedListener(this); JButton pedigree = ViewUtil.getSoftButton("Pedigree"); if (patient.getFamilyID() == null || patient.getFamilyID().isEmpty()) { pedigree.setEnabled(false); } else { pedigree.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JDialog f = new JDialog(MedSavantFrame.getInstance(), "Pedigree Viewer", true); PedigreeCanvas pc = new PedigreeCanvas(); pc.setFamilyName(patient.getFamilyID()); pc.showPedigreeFor(patient.getID()); f.setPreferredSize(new Dimension(650, 500)); f.setLayout(new BorderLayout()); f.add(pc, BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(MedSavantFrame.getInstance()); f.setVisible(true); } }); } final JButton dnaIDButton = ViewUtil.getSoftButton("Open with..."); if (patient.getDnaID() == null || patient.getDnaID().isEmpty()) { dnaIDButton.setEnabled(false); } else { dnaIDButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JPopupMenu m = new JPopupMenu(); Set<AppCommHandler> handlers = AppCommRegistry.getInstance().getHandlersForEvent(PatientVariantAnalyzeComm.class); final PatientVariantAnalyzeComm event = new PatientVariantAnalyzeComm(null, patient.getID()); for (final AppCommHandler handler : handlers) { JMenuItem item = new JMenuItem(handler.getHandlerName()); ImageIcon icon = handler.getHandlerIcon(); if (icon != null) { int iconSize = 22; Image img = ViewUtil.getScaledInstance( icon.getImage(), iconSize, iconSize, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true); item.setIcon(new ImageIcon(img)); } ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { handler.handleCommEvent(event); } }; item.addActionListener(l); m.add(item); } m.show(dnaIDButton, 0, (int) dnaIDButton.getSize().getHeight()); } }); } final JButton bamViewButton = ViewUtil.getSoftButton("Open with..."); if (patient.getBamURL() == null || patient.getBamURL().isEmpty()) { bamViewButton.setEnabled(false); } else { bamViewButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JPopupMenu m = new JPopupMenu(); Set<AppCommHandler> handlers = AppCommRegistry.getInstance().getHandlersForEvent(BAMFileComm.class); URL u = null; try { u = new URL(patient.getBamURL()); } catch (MalformedURLException ex) { } final BAMFileComm event = new BAMFileComm(null, u); for (final AppCommHandler handler : handlers) { JMenuItem item = new JMenuItem(handler.getHandlerName()); ImageIcon icon = handler.getHandlerIcon(); if (icon != null) { int iconSize = 22; Image img = ViewUtil.getScaledInstance( icon.getImage(), iconSize, iconSize, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true); item.setIcon(new ImageIcon(img)); } ActionListener l = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { handler.handleCommEvent(event); } }; item.addActionListener(l); m.add(item); } m.show(bamViewButton, 0, (int) bamViewButton.getSize().getHeight()); } }); } profileKVP.setValue(PatientView.HOSPITAL_ID, individualIDField); profileKVP.setValue(PatientView.SEX, sexField); profileKVP.setValue(PatientView.AFFECTED, affectedField); profileKVP.setValue(PatientView.MOTHER_ID, motherField); profileKVP.setValue(PatientView.FATHER_ID, fatherField); profileKVP.setValue(PatientView.FAMILY_ID, familyIDField); profileKVP.setAdditionalColumn(PatientView.FAMILY_ID, 0, pedigree); StringEditableField dnaIDField = new StringEditableField(); dnaIDField.setValue(patient.getDnaID()); dnaIDField.setTag(DNA_ID); dnaIDField.setValue(patient.getDnaID()); dnaIDField.addFieldComittedListener(this); StringEditableField bamURLField = new StringEditableField(); bamURLField.setValidator(new URLValidator()); bamURLField.setValue(patient.getBamURL()); bamURLField.setTag(BAM_URL); bamURLField.addFieldComittedListener(this); geneticsKVP.setValue(PatientView.DNA_ID, dnaIDField); geneticsKVP.setAdditionalColumn(PatientView.DNA_ID, 0, dnaIDButton); geneticsKVP.setValue(PatientView.BAM_URL, bamURLField); geneticsKVP.setAdditionalColumn(PatientView.BAM_URL, 0, bamViewButton); StringEditableField phenotypeField = new StringEditableField(); phenotypeField.setValue(patient.getPhenotypes()); phenotypeField.setTag(PHENOTYPE); phenotypeField.setValue(patient.getPhenotypes()); phenotypeField.addFieldComittedListener(this); if (!isCurrentUserAdmin) { individualIDField.setAutonomousEditingEnabled(false); sexField.setAutonomousEditingEnabled(false); affectedField.setAutonomousEditingEnabled(false); motherField.setAutonomousEditingEnabled(false); fatherField.setAutonomousEditingEnabled(false); individualIDField.setAutonomousEditingEnabled(false); familyIDField.setAutonomousEditingEnabled(false); bamURLField.setAutonomousEditingEnabled(false); dnaIDField.setAutonomousEditingEnabled(false); phenotypeField.setAutonomousEditingEnabled(false); } phenotypeKVP.setValue(PatientView.PHENOTYPE, phenotypeField); try { List<Cohort> cohorts = MedSavantClient.PatientManager.getCohortsForPatient(LoginController.getSessionID(), ProjectController.getInstance().getCurrentProjectID(), patient.getID()); cohortListPanel.removeAll(); cohortListPanel.setLayout(new MigLayout("wrap, insets 0")); if (cohorts.isEmpty()) { JLabel noCohortMemberLabel = ViewUtil.getGrayItalicizedLabel("This individual is not in a cohort"); cohortListPanel.add(noCohortMemberLabel); } else { for (Cohort c : cohorts) { cohortListPanel.add(new JLabel(c.getName())); } } } catch (SessionExpiredException ex) { MedSavantExceptionHandler.handleSessionExpiredException(ex); } catch (Exception ex) { ex.printStackTrace(); } this.updateUI(); } @Override public void handleCommitEvent(EditableField f) { if (f.getTag().equals(FATHER_ID)) { patient.setFatherHospitalID((String) f.getValue()); } else if (f.getTag().equals(MOTHER_ID)) { patient.setMotherHospitalID((String) f.getValue()); } else if (f.getTag().equals(FAMILY_ID)) { patient.setFamilyID((String) f.getValue()); } else if (f.getTag().equals(AFFECTED)) { patient.setAffected(((String) f.getValue()).equals("Yes")); } else if (f.getTag().equals(HOSPITAL_ID)) { patient.setHospitalID((String) f.getValue()); } else if (f.getTag().equals(SEX)) { patient.setSex((String) f.getValue()); } else if (f.getTag().equals(DNA_ID)) { patient.setDnaID((String) f.getValue()); } else if (f.getTag().equals(BAM_URL)) { patient.setBamURL((String) f.getValue()); } else if (f.getTag().equals(PHENOTYPE)) { patient.setPhenotypes((String) f.getValue()); } patient.saveToDatabase(); } }