/* * KAM Navigator Plugin * * URLs: http://openbel.org/ * Copyright (C) 2012, Selventa * * This program 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ package org.openbel.cytoscape.navigator; import java.awt.BorderLayout; import java.awt.GridLayout; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import org.openbel.cytoscape.webservice.KamService; import org.openbel.cytoscape.webservice.KamServiceFactory; import org.openbel.framework.ws.model.Annotation; import org.openbel.framework.ws.model.BelStatement; import org.openbel.framework.ws.model.BelTerm; import org.openbel.framework.ws.model.Citation; import org.openbel.framework.ws.model.KamEdge; import org.openbel.framework.ws.model.KamNode; import cytoscape.CyEdge; import cytoscape.CyNode; import cytoscape.Cytoscape; import cytoscape.view.cytopanels.CytoPanelImp; /** * {@link DetailsView} provides the UI to show kam node/edge info in the result * panel of cytoscape. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ public class DetailsView { private static DetailsView instance; private final KamService kamService; private final CytoPanelImp resultsPanel; private final JPanel nodeDetailPanel; private final JPanel edgeDetailPanel; private final TermTableModel termTableModel; private final StatementTableModel stmtTableModel; private final AnnotationTableModel annTableModel; private final CitationTableModel citTableModel; public static DetailsView getInstance() { if (instance == null) { instance = new DetailsView(); } return instance; } private DetailsView() { resultsPanel = (CytoPanelImp) Cytoscape.getDesktop() .getCytoPanel(SwingConstants.EAST); this.kamService = KamServiceFactory.getInstance().getKAMService(); // build node details panel and add to results panel nodeDetailPanel = new JPanel(); nodeDetailPanel.setName("KAM Node Info"); JScrollPane tblScroll = new JScrollPane(); JTable termTbl = new JTable(); termTbl.setShowGrid(true); termTbl.setShowHorizontalLines(true); termTbl.setShowVerticalLines(true); nodeDetailPanel.setLayout(new BorderLayout()); JLabel nodeLbl = new JLabel("Supporting BEL Terms"); nodeDetailPanel.add(nodeLbl, BorderLayout.NORTH); termTableModel = new TermTableModel(); termTbl.setModel(termTableModel); tblScroll.setViewportView(termTbl); nodeDetailPanel.add(tblScroll, BorderLayout.CENTER); resultsPanel.add(nodeDetailPanel); // build edge details panel and add to results panel edgeDetailPanel = new JPanel(new GridLayout(3, 1)); edgeDetailPanel.setName("KAM Edge Info"); TextAreaCellRenderer textRenderer = new TextAreaCellRenderer(); // statement panel JPanel stmtPanel = new JPanel(); stmtPanel.setLayout(new BorderLayout()); JLabel edgeLbl = new JLabel("Supporting BEL Statements"); stmtPanel.add(edgeLbl, BorderLayout.NORTH); JScrollPane stmtScroll = new JScrollPane(); JTable stmtTbl = new JTable(); stmtTbl.setShowGrid(true); stmtTbl.setShowHorizontalLines(true); stmtTbl.setShowVerticalLines(true); stmtTableModel = new StatementTableModel(); stmtTbl.setModel(stmtTableModel); stmtTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); stmtTbl.getSelectionModel().addListSelectionListener( new StatementSelectionListener()); stmtScroll.setViewportView(stmtTbl); stmtPanel.add(stmtScroll, BorderLayout.CENTER); edgeDetailPanel.add(stmtPanel); // annotation panel JPanel annPanel = new JPanel(); annPanel.setLayout(new BorderLayout()); JLabel annLbl = new JLabel("Statement Annotations"); annPanel.add(annLbl, BorderLayout.NORTH); JScrollPane annScroll = new JScrollPane(); JTable annTbl = new JTable(); annTbl.setShowGrid(true); annTbl.setShowHorizontalLines(true); annTbl.setShowVerticalLines(true); annTableModel = new AnnotationTableModel(); annTbl.setModel(annTableModel); annTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); annTbl.getColumnModel().getColumn(1).setCellRenderer(textRenderer); annScroll.setViewportView(annTbl); annPanel.add(annScroll, BorderLayout.CENTER); edgeDetailPanel.add(annPanel); // citation panel JPanel citPanel = new JPanel(); citPanel.setLayout(new BorderLayout()); JLabel citLbl = new JLabel("Citation"); citPanel.add(citLbl, BorderLayout.NORTH); JScrollPane citScroll = new JScrollPane(); JTable citTbl = new JTable(); citTbl.setShowGrid(true); citTbl.setShowHorizontalLines(true); citTbl.setShowVerticalLines(true); citTableModel = new CitationTableModel(); citTbl.setModel(citTableModel); citTbl.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); citTbl.getColumnModel().getColumn(0).setCellRenderer(textRenderer); citTbl.getColumnModel().getColumn(1).setCellRenderer(textRenderer); citTbl.getColumnModel().getColumn(2).setCellRenderer(textRenderer); citTbl.getColumnModel().getColumn(3).setCellRenderer(textRenderer); citScroll.setViewportView(citTbl); citPanel.add(citScroll, BorderLayout.CENTER); edgeDetailPanel.add(citPanel); // add edge details to Results Panel (cytoscape) resultsPanel.add(edgeDetailPanel); // delay showing panels nodeDetailPanel.setVisible(false); edgeDetailPanel.setVisible(false); } /** * Callback to handle showing node details for the active cytoscape node. * * @see NetworkDetailsListener#onSelectEvent(cytoscape.data.SelectEvent) * @param node the {@link CyNode cytoscape node} that is active */ public void showNodeDetails(final CyNode node) { clearEdgeModels(); final KamNode kamNode = NetworkUtility.getKAMNode(node); if (kamNode == null) { // node is not kam backed termTableModel.clear(); return; } final List<BelTerm> terms = kamService.getSupportingTerms(kamNode); // set node details and show results panel termTableModel.setTerms(terms); // show node details panel int nodeTabIdx = resultsPanel.indexOfComponent(nodeDetailPanel); resultsPanel.setSelectedIndex(nodeTabIdx); nodeDetailPanel.setVisible(true); } /** * Callback to handle showing edge details for the active cytoscape edge. * * @see NetworkDetailsListener#onSelectEvent(cytoscape.data.SelectEvent) * @param edge the {@link CyEdge cytoscape edge} that is active */ public void showEdgeDetails(final CyEdge edge) { termTableModel.clear(); final KamEdge kamEdge = NetworkUtility.getKAMEdge(edge); if (kamEdge == null) { // edge is not kam backed clearEdgeModels(); return; } final List<BelStatement> statements = kamService .getSupportingEvidence(kamEdge); // set edge details and show results panel stmtTableModel.setStatements(statements); // show edge details panel int edgeTabIdx = resultsPanel.indexOfComponent(edgeDetailPanel); resultsPanel.setSelectedIndex(edgeTabIdx); edgeDetailPanel.setVisible(true); } private void clearEdgeModels() { stmtTableModel.clear(); citTableModel.clear(); annTableModel.clear(); } /** * The {@link AbstractTableModel table model} for the BEL terms of the * active node. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ private class TermTableModel extends AbstractTableModel { private static final long serialVersionUID = 3869233363790339464L; private final String[] headers = new String[] { "BEL Term" }; private final List<BelTerm> terms; public TermTableModel() { this.terms = new ArrayList<BelTerm>(); } public void setTerms(final List<BelTerm> terms) { this.terms.clear(); this.terms.addAll(terms); fireTableDataChanged(); } public void clear() { this.terms.clear(); fireTableDataChanged(); } /** * {@inheritDoc} */ @Override public int getColumnCount() { return headers.length; } /** * {@inheritDoc} */ @Override public String getColumnName(int ci) { return headers[ci]; } /** * {@inheritDoc} */ @Override public int getRowCount() { return terms.size(); } /** * {@inheritDoc} */ @Override public Object getValueAt(int ri, int ci) { final BelTerm term = terms.get(ri); switch (ci) { case 0: return term.getLabel(); } return null; } } /** * The {@link AbstractTableModel table model} for the BEL statements of the * active edge. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ private class StatementTableModel extends AbstractTableModel { private static final long serialVersionUID = 4239815126171784622L; private final String[] headers = new String[] { "Subject", "Relationship", "Object" }; private final List<BelStatement> statements; public StatementTableModel() { this.statements = new ArrayList<BelStatement>(); } public void setStatements(final List<BelStatement> statements) { this.statements.clear(); this.statements.addAll(statements); // loaded new statements so reset statement annotations and citations annTableModel.setAnnotations(new ArrayList<Annotation>()); citTableModel.setCitations(new ArrayList<Citation>()); fireTableDataChanged(); } public void clear() { this.statements.clear(); fireTableDataChanged(); } /** * {@inheritDoc} */ @Override public int getColumnCount() { return headers.length; } /** * {@inheritDoc} */ @Override public String getColumnName(int ci) { return headers[ci]; } /** * {@inheritDoc} */ @Override public int getRowCount() { return statements.size(); } /** * {@inheritDoc} */ @Override public Object getValueAt(int ri, int ci) { final BelStatement stmt = statements.get(ri); switch (ci) { case 0: return stmt.getSubjectTerm().getLabel(); case 1: // can return null return stmt.getRelationship(); case 2: final BelTerm objTerm = stmt.getObjectTerm(); final BelStatement objStmt = stmt.getObjectStatement(); if (objTerm != null) { return objTerm.getLabel(); } else if (objStmt != null) { if (objStmt.getSubjectTerm() == null || objStmt.getRelationship() == null || objStmt.getObjectTerm() == null) { return null; } return objStmt.getSubjectTerm().getLabel() + " " + objStmt.getRelationship() + " " + objStmt.getObjectTerm().getLabel(); } } return null; } } /** * The {@link AbstractTableModel table model} for citations that display * for the selected BEL statement in the * {@link StatementTableModel statement table model}. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ private class CitationTableModel extends AbstractTableModel { private static final long serialVersionUID = -7502992026898866459L; private final String[] headers = new String[] { "Id", "Name", "Publication Date", "Authors" }; private final List<Citation> citations; public CitationTableModel() { this.citations = new ArrayList<Citation>(); } public void setCitations(final List<Citation> citations) { this.citations.clear(); this.citations.addAll(citations); fireTableDataChanged(); } public void clear() { this.citations.clear(); fireTableDataChanged(); } /** * {@inheritDoc} */ @Override public int getColumnCount() { return headers.length; } /** * {@inheritDoc} */ @Override public String getColumnName(int ci) { return headers[ci]; } /** * {@inheritDoc} */ @Override public int getRowCount() { return citations.size(); } /** * {@inheritDoc} */ @Override public Object getValueAt(int ri, int ci) { final Citation cit = citations.get(ri); switch (ci) { case 0: return cit.getCitationType() + " - " + cit.getId(); case 1: return cit.getName(); case 2: return cit.getPublicationDate() == null ? null : cit.getPublicationDate().toString(); case 3: if (cit.getAuthors() == null) { return null; } StringBuilder sb = new StringBuilder(); for (Iterator<String> it = cit.getAuthors().iterator(); it.hasNext();) { sb.append(it.next()); if (it.hasNext()) { sb.append(", "); } } return sb.toString(); } return null; } } /** * The {@link AbstractTableModel table model} for annotations that display * for the selected BEL statement in the * {@link StatementTableModel statement table model}. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ private class AnnotationTableModel extends AbstractTableModel { private static final long serialVersionUID = -2058889152696174033L; private final String[] headers = new String[] { "Name", "Value" }; private final List<Annotation> annotations; public AnnotationTableModel() { this.annotations = new ArrayList<Annotation>(); } public void setAnnotations(final List<Annotation> annotations) { this.annotations.clear(); this.annotations.addAll(annotations); fireTableDataChanged(); } public void clear() { this.annotations.clear(); fireTableDataChanged(); } /** * {@inheritDoc} */ @Override public int getColumnCount() { return headers.length; } /** * {@inheritDoc} */ @Override public String getColumnName(int ci) { return headers[ci]; } /** * {@inheritDoc} */ @Override public int getRowCount() { return annotations.size(); } /** * {@inheritDoc} */ @Override public Object getValueAt(int ri, int ci) { final Annotation ann = annotations.get(ri); switch (ci) { case 0: return ann.getAnnotationType().getName(); case 1: // can return null return ann.getValue(); } return null; } } /** * The selection listener for the * {@link StatementTableModel statement table model} that determines the * selected {@link BelStatement statement} and refreshes the * {@link CitationTableModel citation table model} and the * {@link AnnotationTableModel annotation table model}. * * @author Anthony Bargnesi <abargnesi@selventa.com> */ private class StatementSelectionListener implements ListSelectionListener { /** * {@inheritDoc} */ @Override public void valueChanged(ListSelectionEvent e) { final ListSelectionModel selModel = (ListSelectionModel) e.getSource(); int selectedIndex = selModel.getMinSelectionIndex(); if (selectedIndex != -1) { final List<BelStatement> stmts = stmtTableModel.statements; final BelStatement selected = stmts.get(selectedIndex); annTableModel.setAnnotations(selected.getAnnotations()); final Citation citation = selected.getCitation(); citTableModel.setCitations(Arrays.asList(new Citation[] {citation})); } } } }