1 /* OrthoParalogTable.java
2  * This file is part of Artemis
3  *
4  * Copyright (C) 2007  Genome Research Limited
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  */
21 
22 package uk.ac.sanger.artemis.components.genebuilder.ortholog;
23 
24 import java.awt.Color;
25 import java.awt.Component;
26 import java.awt.Cursor;
27 import java.awt.Dimension;
28 import java.awt.Font;
29 import java.awt.event.ActionEvent;
30 import java.awt.event.ActionListener;
31 import java.awt.event.MouseAdapter;
32 import java.awt.event.MouseEvent;
33 import java.awt.event.MouseMotionAdapter;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.Comparator;
37 import java.util.List;
38 import java.util.Vector;
39 
40 import javax.swing.JButton;
41 import javax.swing.JCheckBox;
42 import javax.swing.JLabel;
43 import javax.swing.JMenuItem;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPopupMenu;
46 import javax.swing.JTable;
47 import javax.swing.JTextArea;
48 import javax.swing.JTextField;
49 import javax.swing.ListSelectionModel;
50 import javax.swing.SwingConstants;
51 import javax.swing.UIManager;
52 import javax.swing.table.DefaultTableCellRenderer;
53 import javax.swing.table.DefaultTableModel;
54 import javax.swing.table.TableColumn;
55 import javax.swing.table.TableModel;
56 
57 import org.gmod.schema.sequence.FeatureLoc;
58 
59 import uk.ac.sanger.artemis.Feature;
60 import uk.ac.sanger.artemis.FeaturePredicate;
61 import uk.ac.sanger.artemis.chado.ArtemisUtils;
62 import uk.ac.sanger.artemis.chado.ClusterLazyQualifierValue;
63 import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
64 import uk.ac.sanger.artemis.io.DocumentEntry;
65 import uk.ac.sanger.artemis.io.GFFStreamFeature;
66 import uk.ac.sanger.artemis.io.InvalidRelationException;
67 import uk.ac.sanger.artemis.io.PartialSequence;
68 import uk.ac.sanger.artemis.io.Qualifier;
69 import uk.ac.sanger.artemis.io.QualifierLazyLoading;
70 import uk.ac.sanger.artemis.io.QualifierVector;
71 import uk.ac.sanger.artemis.sequence.AminoAcidSequence;
72 import uk.ac.sanger.artemis.util.DatabaseDocument;
73 import uk.ac.sanger.artemis.util.StringVector;
74 
75 public class OrthoParalogTable extends AbstractMatchTable
76 {
77   private static int NUMBER_COLUMNS = 10;
78   private Vector rowData   = new Vector();
79   private Vector tableData = new Vector(NUMBER_COLUMNS);
80   private JTable table;
81   private JButton infoLevelButton = new JButton("Details");
82   private JPopupMenu popupMenu = new JPopupMenu();
83   private boolean showCluster;
84 
85   //
86   // column headings
87   protected final static String CLUSTER_NAME_COL = "Cluster";
88   protected final static String MATCH_NAME_COL = "Match";
89   protected final static String ROW_TYPE_HIDE_COL = "Term";
90   protected final static String ROW_TYPE_COL = "Type";
91   protected final static String PROGRAM_COL = "Program";
92   protected final static String ORGANISM_COL = "Organism";
93   protected final static String PRODUCT_COL = "Product";
94   protected final static String GENE_COL = "Gene";
95   protected final static String LINK_COL = "Link";
96   protected final static String VIEW_BUTTON_COL = "View";
97   protected final static String REMOVE_BUTTON_COL = "";
98 
99 
100   /**
101    * Contruct a component for an ortholog or paralog line
102    * @param doc
103    * @param orthologQualifier
104    * @param paralogQualifier
105    * @param feature
106    * @param showCluster
107    */
OrthoParalogTable(final DatabaseDocument doc, final Qualifier orthologQualifier, final Qualifier paralogQualifier, final Feature feature, final boolean showCluster)108   protected OrthoParalogTable(final DatabaseDocument doc,
109                               final Qualifier orthologQualifier,
110                               final Qualifier paralogQualifier,
111                               final Feature feature,
112                               final boolean showCluster)
113   {
114     this.origQualifiers = new QualifierVector();
115     this.showCluster = showCluster;
116 
117     if(orthologQualifier != null)
118       this.origQualifiers.add(orthologQualifier);
119     if(paralogQualifier != null)
120       this.origQualifiers.add(paralogQualifier);
121 
122     createPopupMenu(doc, feature);
123 
124     infoLevelButton.setOpaque(false);
125     tableData.setSize(NUMBER_COLUMNS);
126 
127     tableData.setElementAt(CLUSTER_NAME_COL,0);
128     tableData.setElementAt(MATCH_NAME_COL,1);
129     tableData.setElementAt(ROW_TYPE_HIDE_COL,2);
130     if(showCluster)
131       tableData.setElementAt(PROGRAM_COL,3);
132     else
133       tableData.setElementAt(ROW_TYPE_COL,3);
134     tableData.setElementAt(ORGANISM_COL,4);
135     tableData.setElementAt(GENE_COL,5);
136     tableData.setElementAt(LINK_COL,6);
137     tableData.setElementAt(PRODUCT_COL,7);
138     tableData.setElementAt(VIEW_BUTTON_COL,8);
139     tableData.setElementAt(REMOVE_BUTTON_COL,9);
140 
141     // add row data
142     int columnIndex;
143 
144     for(int i=0; i<origQualifiers.size(); i++)
145     {
146       final Vector qualifierValuesToDelete = new Vector();
147 
148       final Qualifier origQualifier = (Qualifier) origQualifiers.elementAt(i);
149 
150       // ensure the gene name is loaded as well
151       if(origQualifier instanceof QualifierLazyLoading)
152       {
153         List lazyValues = ((QualifierLazyLoading)origQualifier).getLazyValues();
154         for(int j=0; j<lazyValues.size(); j++)
155         {
156           ClusterLazyQualifierValue lazyValue = (ClusterLazyQualifierValue)lazyValues.get(j);
157 
158           if(!lazyValue.isLazyLoaded())
159             lazyValue.setLoadGeneName(true);
160         }
161       }
162 
163       final StringVector values = origQualifier.getValues();
164 
165       // sort by their rank value
166       Collections.sort(values, new OrthoParalogValueComparator());
167 
168       for(int j = 0; j < values.size(); j++)
169       {
170         StringVector rowStr = StringVector.getStrings((String) values.get(j),
171             ";");
172 
173         if(rowStr.size() < 1)
174         {
175           qualifierValuesToDelete.add(values.get(j));
176           continue;
177         }
178         if( (ArtemisUtils.getString(rowStr, "cluster_name=").equals("") && !showCluster) ||
179             (!ArtemisUtils.getString(rowStr, "cluster_name=").equals("") && showCluster) )
180           processRowData(rowStr, rowData, origQualifier.getName());
181       }
182 
183       values.removeAll(qualifierValuesToDelete);
184     }
185 
186     table = new JTable(rowData, tableData);
187     setTable(table);
188 
189     // set hand cursor
190     table.addMouseMotionListener( new MouseMotionAdapter()
191     {
192       private Cursor handCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
193       public void mouseMoved(MouseEvent e)
194       {
195         int col = table.columnAtPoint(e.getPoint());
196         final String colName = table.getColumnName(col);
197 
198         if(colName.equals(GENE_COL) || colName.equals(REMOVE_BUTTON_COL))
199           table.setCursor(handCursor);
200         else
201           table.setCursor(Cursor.getDefaultCursor());
202       }
203     });
204 
205     table.addMouseListener(new MouseAdapter()
206     {
207       public void mousePressed(MouseEvent e)
208       {
209         showPopup(e);
210       }
211 
212       public void mouseReleased(MouseEvent e)
213       {
214         showPopup(e);
215       }
216 
217       private void showPopup(MouseEvent e)
218       {
219         if(e.isPopupTrigger())
220           popupMenu.show(e.getComponent(), e.getX(), e.getY());
221       }
222     });
223 
224     final TableColumn[] hideColumns = new TableColumn[4];
225 
226     hideColumns[0] = table.getColumn(ROW_TYPE_HIDE_COL);
227     hideColumns[1] = table.getColumn(MATCH_NAME_COL);
228     if(showCluster)
229       hideColumns[2] = table.getColumn(REMOVE_BUTTON_COL);
230     else
231       hideColumns[2] = table.getColumn(CLUSTER_NAME_COL);
232     hideColumns[3] = table.getColumn(PRODUCT_COL);
233 
234     for(int i=0; i<hideColumns.length; i++)
235     {
236       if(i == 3 && !showCluster)
237         continue;
238       hideColumns[i].setMinWidth(0);
239       hideColumns[i].setMaxWidth(0);
240     }
241 
242     table.setColumnSelectionAllowed(false);
243     table.setRowSelectionAllowed(true);
244     table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
245     table.setDragEnabled(true);
246     table.setTransferHandler(new TableTransferHandler());
247 
248     TableModel tableModel = table.getModel();
249     // remove button column
250     TableColumn col;
251     if(!showCluster)
252     {
253       col = table.getColumn(REMOVE_BUTTON_COL);
254       col.setMinWidth(35);
255       col.setMaxWidth(40);
256       col.setPreferredWidth(40);
257     }
258 
259     final OrthologRenderer renderer = new OrthologRenderer();
260 
261     for(columnIndex = 0; columnIndex <tableModel.getColumnCount();
262         columnIndex++)
263     {
264       col = table.getColumnModel().getColumn(columnIndex);
265       col.setCellRenderer(renderer);
266       col.setCellEditor(new CellEditing(new JTextField()));
267     }
268 
269     packColumn(table, getColumnIndex(GENE_COL), 4);
270     packColumn(table, getColumnIndex(LINK_COL), 4);
271     packColumn(table, getColumnIndex(ORGANISM_COL), 4);
272     packColumn(table, getColumnIndex(VIEW_BUTTON_COL), 4);
273 
274     if(showCluster)
275     {
276       packColumn(table, getColumnIndex(CLUSTER_NAME_COL), 4);
277       packColumn(table, getColumnIndex(PROGRAM_COL), 4);
278     }
279     else
280     {
281       packColumn(table, getColumnIndex(ROW_TYPE_COL), 4);
282       packColumn(table, getColumnIndex(PRODUCT_COL), 4);
283     }
284 
285     // remove JButton column
286     col = table.getColumn(REMOVE_BUTTON_COL);
287     col.setCellEditor(new ButtonEditor(new JCheckBox(),
288         (DefaultTableModel)table.getModel(), "X", doc));
289 
290     // remove JButton column
291     col = table.getColumn(VIEW_BUTTON_COL);
292     col.setCellEditor(new ButtonEditor(new JCheckBox(),
293         (DefaultTableModel)table.getModel(), "VIEW", doc));
294 
295     // orthologue link
296     col = table.getColumn(GENE_COL);
297     col.setCellEditor(new LinkEditor(new JCheckBox(),
298         (DefaultTableModel)table.getModel(), doc));
299   }
300 
301   /**
302    * Parse the qualifier string into row data
303    * @param rowStr
304    * @param rowData
305    * @param qualifierName
306    */
processRowData(final StringVector rowStr, final Vector rowData, final String qualifierName)307   private void processRowData(final StringVector rowStr,
308                               final Vector rowData,
309                               final String qualifierName)
310   {
311     final String orthoparalogs[] = ((String) rowStr.get(0)).split(",");
312 
313     String clusterName = "";
314     if(rowStr.size() > 1)
315     {
316       clusterName = ArtemisUtils.getString(rowStr, "cluster_name=");
317       if(!clusterName.equals(""))
318         clusterName = clusterName.substring(13);
319     }
320 
321     String matchName = "";
322     if(rowStr.size() > 1)
323     {
324       matchName = ArtemisUtils.getString(rowStr, "match_name=");
325       if(!matchName.equals(""))
326         matchName = matchName.substring(11);
327     }
328 
329     String program = "";
330     if(rowStr.size() > 1)
331     {
332       program = ArtemisUtils.getString(rowStr, "program=");
333       if(!program.equals(""))
334         program = program.substring(8);
335     }
336 
337     String product = "";
338     if(rowStr.size() > 1)
339     {
340       product = ArtemisUtils.getString(rowStr, "product=");
341       if(!product.equals(""))
342         product = product.substring(8);
343     }
344 
345     int columnIndex;
346     for(int k = 0; k < orthoparalogs.length; k++)
347     {
348       Vector thisRowData = new Vector(NUMBER_COLUMNS);
349 
350       String geneNameAndLinkAndType[] = orthoparalogs[k].split("link=");
351       String linkAndType[] = geneNameAndLinkAndType[1].split("type=");
352       String gene[] = geneNameAndLinkAndType[0].trim().split(":");
353 
354       thisRowData.setSize(NUMBER_COLUMNS);
355 
356       columnIndex = tableData.indexOf(ORGANISM_COL);
357       thisRowData.setElementAt(gene[0], columnIndex);
358 
359       columnIndex = tableData.indexOf(GENE_COL);
360       thisRowData.setElementAt(geneNameAndLinkAndType[0].trim(), columnIndex);
361 
362       columnIndex = tableData.indexOf(LINK_COL);
363       thisRowData.setElementAt(linkAndType[0].trim(), columnIndex);
364 
365       columnIndex = tableData.indexOf(CLUSTER_NAME_COL);
366       thisRowData.setElementAt(clusterName, columnIndex);
367 
368       columnIndex = tableData.indexOf(MATCH_NAME_COL);
369       thisRowData.setElementAt(matchName, columnIndex);
370 
371       columnIndex = tableData.indexOf(ROW_TYPE_HIDE_COL);
372       thisRowData.setElementAt(qualifierName, columnIndex);
373 
374       columnIndex = tableData.indexOf(PRODUCT_COL);
375       thisRowData.setElementAt(product, columnIndex);
376 
377       columnIndex = tableData.indexOf(ROW_TYPE_COL);
378 
379       if(columnIndex > -1)
380       {
381         final String symbol;
382         if(linkAndType[1].trim().equals(MatchPanel.ORTHOLOG))
383           symbol = "O";
384         else
385          symbol = "P";
386         thisRowData.setElementAt(symbol, columnIndex);
387       }
388 
389       columnIndex = tableData.indexOf(PROGRAM_COL);
390       if(columnIndex > -1)
391         thisRowData.setElementAt(program, columnIndex);
392 
393       rowData.add(thisRowData);
394     }
395   }
396 
397   /**
398    * Find if this contains any clusters
399    * @return
400    */
hasCluster(final Qualifier orthoQualifier, final Qualifier paraQualifier, final GFFStreamFeature feature)401   protected static boolean hasCluster(final Qualifier orthoQualifier,
402                                       final Qualifier paraQualifier,
403                                       final GFFStreamFeature feature)
404   {
405     if(hasClusterOrOrthoParalog(true, orthoQualifier, feature))
406       return true;
407     return hasClusterOrOrthoParalog(true, paraQualifier, feature);
408   }
409 
410   /**
411    * Find if this contains any ortholog or paralog
412    * @return
413    */
hasOrthoParlaog(final Qualifier orthoQualifier, final Qualifier paraQualifier, final GFFStreamFeature feature)414   protected static boolean hasOrthoParlaog(final Qualifier orthoQualifier,
415                                            final Qualifier paraQualifier,
416                                            final GFFStreamFeature feature)
417   {
418     if(hasClusterOrOrthoParalog(false, orthoQualifier, feature))
419     {
420       forceBulkLoad(paraQualifier, feature);
421       return true;
422     }
423     return hasClusterOrOrthoParalog(false, paraQualifier, feature);
424   }
425 
hasClusterOrOrthoParalog(final boolean lookForCluster, final Qualifier qualifier, final GFFStreamFeature feature)426   private static boolean hasClusterOrOrthoParalog(final boolean lookForCluster,
427                                                   final Qualifier qualifier,
428                                                   final GFFStreamFeature feature)
429   {
430     if(qualifier == null)
431       return false;
432 
433     forceBulkLoad(qualifier, feature);
434 
435     StringVector values = qualifier.getValues();
436 
437     for(int j = 0; j < values.size(); j++)
438     {
439       StringVector rowStr = StringVector.getStrings((String) values.get(j),
440           ";");
441 
442       if( (!ArtemisUtils.getString(rowStr, "cluster_name=").equals("") && lookForCluster) ||
443           (ArtemisUtils.getString(rowStr, "cluster_name=").equals("")  && !lookForCluster) )
444         return true;
445     }
446 
447     return false;
448   }
449 
450   /**
451    * For long lists of ortho/paralogs this speeds-up their loading
452    * @param qualifier
453    * @param feature
454    */
forceBulkLoad(final Qualifier qualifier, final GFFStreamFeature feature)455   private static void forceBulkLoad(final Qualifier qualifier,
456                              final GFFStreamFeature feature)
457   {
458     if(qualifier instanceof QualifierLazyLoading &&
459         !((QualifierLazyLoading)qualifier).isAllLazyValuesLoaded())
460     {
461       List values = ((QualifierLazyLoading)qualifier).getLazyValues();
462       final DatabaseDocument document =
463         (DatabaseDocument)((DocumentEntry)feature.getEntry()).getDocument();
464       ClusterLazyQualifierValue.setClusterFromValueList(values, document);
465     }
466   }
467 
468   /**
469    * Find the parent feature
470    * @param feature
471    * @return
472    */
getParentFeature(final Feature feature)473   private Feature getParentFeature(final Feature feature)
474   {
475     final QualifierVector qualifiers = feature.getQualifiers();
476 
477 
478     String featureId = null;
479     for(int i=0; i<qualifiers.size(); i++)
480     {
481       Qualifier qualifier = (Qualifier)qualifiers.elementAt(i);
482       if(qualifier.getName().equalsIgnoreCase("Derives_from") ||
483          qualifier.getName().equalsIgnoreCase("Parent"))
484       {
485         featureId = (String) qualifier.getValues().get(0);
486         break;
487       }
488     }
489     FeatureNamePredicate predicate = new FeatureNamePredicate(featureId);
490     final uk.ac.sanger.artemis.FeatureVector features = feature.getEntry().getAllFeatures();
491     for(int i=0; i<features.size(); i++)
492     {
493       Feature thisFeature = features.elementAt(i);
494       if(predicate.testPredicate(thisFeature))
495         return thisFeature;
496     }
497     return null;
498   }
499 
500 
501   /**
502    * Create the popup menu for the table
503    *
504    */
createPopupMenu(final DatabaseDocument doc, final Feature feature)505   private void createPopupMenu(final DatabaseDocument doc,
506                                final Feature feature)
507   {
508     JMenuItem showSequenceMenu = new JMenuItem("Show selected sequences");
509     popupMenu.add(showSequenceMenu);
510     showSequenceMenu.addActionListener(new ActionListener()
511     {
512       public void actionPerformed(ActionEvent e)
513       {
514         Cursor orginalCursor = table.getCursor();
515         table.setCursor(new Cursor(Cursor.WAIT_CURSOR));
516         showAlignmentEditor(feature, doc, false);
517         table.setCursor(orginalCursor);
518       }
519     });
520 
521 
522     JMenuItem showAASequenceMenu = new JMenuItem("Show selected amino acid sequences");
523     popupMenu.add(showAASequenceMenu);
524     showAASequenceMenu.addActionListener(new ActionListener()
525     {
526       public void actionPerformed(ActionEvent e)
527       {
528         Cursor orginalCursor = table.getCursor();
529         table.setCursor(new Cursor(Cursor.WAIT_CURSOR));
530         showAlignmentEditor(feature, doc, true);
531         table.setCursor(orginalCursor);
532       }
533     });
534 
535     JMenuItem openMenu = new JMenuItem("Open selected in Artemis");
536     popupMenu.add(openMenu);
537     openMenu.addActionListener(new ActionListener()
538     {
539       public void actionPerformed(ActionEvent e)
540       {
541         Cursor orginalCursor = table.getCursor();
542         table.setCursor(new Cursor(Cursor.WAIT_CURSOR));
543         int selectedRows[] = getTable().getSelectedRows();
544 
545         if(selectedRows.length > 1)
546         {
547           int select = JOptionPane.showConfirmDialog(null,
548               "Open all selected sequences in seperate Artemis windows?",
549               "Open Artemis x"+selectedRows.length, JOptionPane.OK_CANCEL_OPTION);
550           if(select == JOptionPane.CANCEL_OPTION)
551             return;
552         }
553         for(int i=0; i<selectedRows.length; i++)
554           openArtemis(doc,selectedRows[i]);
555         table.setCursor(orginalCursor);
556       }
557     });
558   }
559 
560   /**
561    * Display this feature and selected features in the table in
562    * Jemboss alignment editor.
563    * @param feature
564    * @param doc
565    * @param showPeptideSequence
566    */
showAlignmentEditor(final Feature feature, final DatabaseDocument doc, final boolean showPeptideSequence)567   private void showAlignmentEditor(final Feature feature,
568                                    final DatabaseDocument doc,
569                                    final boolean showPeptideSequence)
570   {
571     final int[] rows = table.getSelectedRows();
572     final int orthoColumn = getColumnIndex(GENE_COL);
573     final Vector seqs = new Vector();
574 
575     // find the gene feature
576     Feature gene = feature;
577     if(!feature.getKey().equals("gene"))
578     {
579       gene = getParentFeature(feature);
580       if(!gene.getKey().equals("gene"))
581         gene = getParentFeature(gene);
582     }
583 
584     // find the exons for the gene
585     if(gene != null)
586     {
587       ChadoCanonicalGene chadoGene = ((GFFStreamFeature)gene.getEmblFeature()).getChadoGene();
588       StringBuffer buffer = new StringBuffer();
589       try
590       {
591         String transcriptName =
592           chadoGene.getTranscriptFromName((String) feature.getQualifierByName("ID").getValues().get(0));
593 
594         List exons = chadoGene.getSplicedFeaturesOfTranscript(transcriptName);
595 
596         for (int i = 0 ; i < exons.size () ; ++i)
597         {
598           final uk.ac.sanger.artemis.io.Feature this_feature =
599             (uk.ac.sanger.artemis.io.Feature)exons.get(i);
600           buffer.append (((Feature)this_feature.getUserData()).getBases ());
601         }
602 
603         final String seqStr;
604         if(showPeptideSequence)
605           seqStr = AminoAcidSequence.getTranslation (buffer.toString(), true).toString();
606         else
607           seqStr = buffer.toString();
608 
609         final String sysName = gene.getSystematicName();
610         seqs.add(new org.emboss.jemboss.editor.Sequence(sysName, seqStr));
611       }
612       catch(InvalidRelationException e)
613       {
614         e.printStackTrace();
615       }
616     }
617 
618     for(int i=0; i<rows.length; i++)
619     {
620       String ortho = (String)table.getValueAt(rows[i], orthoColumn);
621       final String reference[] = ortho.split(":");
622       DatabaseDocument newdoc = new DatabaseDocument(doc,
623           reference[0], reference[1], true, stream_progress_listener);
624 
625       try
626       {
627         // gene sequence
628         PartialSequence sequence = newdoc.getChadoSequence(reference[1]);
629 
630         // cds featureloc's
631         List featureLocs =
632           newdoc.getCdsFeatureLocsByPeptideName(
633               (String)table.getValueAt(rows[i], getColumnIndex(LINK_COL)));
634 
635         //
636         int phase = 0;
637         final StringBuffer sequenceBuffer = new StringBuffer();
638         if(featureLocs != null)
639         {
640           for(int j = 0; j < featureLocs.size(); j++)
641           {
642             FeatureLoc featureLoc = (FeatureLoc) featureLocs.get(j);
643             if(featureLoc.getPhase() != null)
644               phase = featureLoc.getPhase().intValue();
645             char[] subSeq = sequence.getCharSubSequence(
646                 (featureLoc.getFmin().intValue() + 1),
647                  featureLoc.getFmax().intValue());
648             sequenceBuffer.append(subSeq);
649           }
650         }
651         else
652         {
653           char[] subSeq = sequence.getSequence();
654           sequenceBuffer.append(subSeq);
655           if(sequence.getPhase() != null)
656             phase = sequence.getPhase().intValue();
657         }
658 
659         final String seqStr;
660         if(showPeptideSequence)
661           seqStr = AminoAcidSequence.getTranslation(
662               sequenceBuffer.toString().substring(phase), true).toString();
663         else
664           seqStr = new String(sequenceBuffer.toString());
665 
666         seqs.add(new org.emboss.jemboss.editor.Sequence(ortho, seqStr));
667       }
668       catch(NullPointerException npe)
669       {
670         JOptionPane.showMessageDialog(null,
671             "Cannot get the sequence for "+ortho,
672             "Warning", JOptionPane.WARNING_MESSAGE);
673         npe.printStackTrace();
674       }
675     }
676 
677     org.emboss.jemboss.editor.AlignJFrame ajFrame =
678           new org.emboss.jemboss.editor.AlignJFrame(seqs);
679     ajFrame.setVisible(true);
680   }
681 
682   /**
683    * Called by AbstractMatchTable.updateQualifier()
684    */
updateQualifierString(final int row)685   protected String updateQualifierString(final int row)
686   {
687     final String type;
688     if( ((String)getTable().getValueAt(row, getColumnIndex(ROW_TYPE_COL))).equals("O") )
689       type = MatchPanel.ORTHOLOG;
690     else
691       type = MatchPanel.PARALOG;
692 
693     StringBuffer orthologStr = new StringBuffer(
694         (String)getTable().getValueAt(row, getColumnIndex(GENE_COL))+
695         " link="+
696         (String)getTable().getValueAt(row, getColumnIndex(LINK_COL))+
697         " type="+type);            // ortholog link
698     orthologStr.append(";");
699 
700     String clusterName = (String)getTable().getValueAt(row, getColumnIndex(CLUSTER_NAME_COL));
701     if(clusterName != null && !clusterName.equals(""))
702       orthologStr.append("cluster_name="+clusterName+ ";" ); // cluster name
703 
704     String product = (String)getTable().getValueAt(row, getColumnIndex(PRODUCT_COL));
705     if(product != null && !product.equals(""))
706       orthologStr.append("product="+product+ ";" );
707 
708 
709     String matchName = (String)getTable().getValueAt(row, getColumnIndex(MATCH_NAME_COL));
710     if(matchName != null && !matchName.equals(""))
711       orthologStr.append("match_name="+matchName+ ";" ); // match name
712 
713     orthologStr.append("rank="+row);
714 
715     return orthologStr.toString();
716   }
717 
718   /**
719    * Override AbstractMatchTables.getOtherValues().
720    * Removes all values apart from those that are not displayed in
721    * the table, i.e. depending on whether a cluster table is displayed
722    * or the ortholog/paralog table.
723    * @param origQualifier
724    * @return
725    */
getOtherValues(final Qualifier origQualifier)726   protected StringVector getOtherValues(final Qualifier origQualifier)
727   {
728     StringVector values = origQualifier.getValues();
729     Vector removeValues = new Vector();
730     for(int j=0; j<values.size(); j++)
731     {
732       String value = (String) values.elementAt(j);
733       if( (value.indexOf("cluster_name=") > -1 && showCluster) ||
734           (value.indexOf("cluster_name=") < 0  && !showCluster) )
735         removeValues.add(value);
736     }
737     values.removeAll(removeValues);
738 
739     return values;
740   }
741 
742   /**
743    * Returns true if the qualifier name matches the row type, e.g.
744    * orthologous_to / paralogous_to
745    * @param qualifierName
746    * @param row
747    * @return
748    */
isRowOfType(String qualifierName, int row)749   protected boolean isRowOfType(String qualifierName, int row)
750   {
751     String rowType = (String)getTable().getValueAt(row, getColumnIndex(ROW_TYPE_HIDE_COL));
752 
753     if(rowType.equals(qualifierName))
754       return true;
755     return false;
756   }
757 
758   /**
759    * Check whether ortholog/paralog qualifier string exists in a StringVector for that qualifier.
760    * If the StringVector contains the hit, description return true.
761    * @param qualStr
762    * @param qualStringVector
763    * @return
764    */
containsStringInStringVector(final String qualStr, final StringVector qualStringVector)765   public static boolean containsStringInStringVector(final String qualStr,
766                                                      final StringVector qualStringVector)
767   {
768     final StringVector orth1 = StringVector.getStrings(qualStr, ";");
769     final String clusterName1 = ArtemisUtils.getString(orth1, "cluster");
770     //final String rank1 = ArtemisUtils.getString(orth1, "rank");
771     String value1 = (String)orth1.get(0);
772     int index;
773 
774     if(!clusterName1.equals("")) // if a part of a cluster
775     {
776       final String clusterElements1[] = value1.split(", ");
777       final List findAll = Arrays.asList(clusterElements1);
778 
779       for(int i=0; i<findAll.size(); i++)
780       {
781         final String findMe = (String)findAll.get(i);
782         boolean found = false;
783         for(int j=0; j<qualStringVector.size(); j++)
784         {
785           String thisStr = (String)qualStringVector.get(j);
786           StringVector orth2 = StringVector.getStrings(thisStr, ";");
787           final String clusterName2 = ArtemisUtils.getString(orth2, "cluster_name");
788           if(!clusterName1.equals(clusterName2))
789             continue;
790 
791           String value2 = (String)orth2.get(0);
792           if((index = value2.indexOf('=')) > -1)
793             value2 = value2.substring(index+1);
794           String clusterElements2[] = value2.split(", ");
795 
796           final List searchList = Arrays.asList(clusterElements2);
797 
798           if(searchList.contains(findMe))
799             found = true;
800         }
801         if(!found)
802           return false;
803       }
804       return true;
805     }
806 
807     for(int i=0; i<qualStringVector.size(); i++)
808     {
809       String thisStr = (String)qualStringVector.get(i);
810 
811       StringVector orth2 = StringVector.getStrings(thisStr, ";");
812 
813       if(orth1.size() != orth2.size())
814         continue;
815 
816       String value2 = (String)orth2.get(0);
817       if((index = value2.indexOf('=')) > -1)
818         value2 = value2.substring(index+1);
819 
820       if(!clusterName1.equals("") && !ArtemisUtils.getString(orth2, "cluster_name").equals(""))
821         System.out.println(value1+"  ==>  "+value2);
822       // ortholog/paralog/cluster
823       if(value1.indexOf(value2) < 0 &&
824          value2.indexOf(value1) < 0 )
825         continue;
826 
827       // cluster name
828       final String clusterName2 = ArtemisUtils.getString(orth2, "cluster_name");
829       if(!clusterName1.equals(clusterName2))
830         continue;
831 
832       // rank
833       /*
834       final String rank2 = ArtemisUtils.getString(orth2, "rank");
835       if(!rank1.equals(rank2))
836         continue;
837       */
838 
839       // description
840       /*
841       if( orth1.size() > 1 && orth2.size() > 1 &&
842           !((String)orth1.get(1)).equals((String)orth2.get(1)) )
843         continue;
844       */
845 
846       return true;
847     }
848     return false;
849   }
850 
851   /**
852    * Renderer for the Ortholog cells
853    */
854   private class OrthologRenderer extends DefaultTableCellRenderer
855   {
856     /** */
857     private static final long serialVersionUID = 1L;
858     private int minHeight = -1;
859 
860     private final JLabel gene = new JLabel();
861     private final JLabel link = new JLabel();
862     private final JLabel type = new JLabel();
863     private final JLabel program = new JLabel();
864     private final JLabel symbol = new JLabel();
865     private final JLabel organism = new JLabel();
866     private final JLabel product = new JLabel();
867     private final JTextArea descriptionTextArea = new JTextArea();
868     private final JLabel clusterName = new JLabel();
869     private final JLabel matchName = new JLabel();
870     private final JLabel buttRemove = new JLabel("X");
871     private final JLabel buttView = new JLabel("VIEW");
872     private Color fgColor = new Color(139,35,35);
873     private Color fgLinkColor = Color.BLUE;
874 
OrthologRenderer()875     public OrthologRenderer()
876     {
877       gene.setForeground(Color.BLUE);
878       gene.setOpaque(true);
879 
880       clusterName.setOpaque(true);
881       organism.setOpaque(true);
882       link.setOpaque(true);
883       product.setOpaque(true);
884 
885       descriptionTextArea.setLineWrap(true);
886       descriptionTextArea.setWrapStyleWord(true);
887 
888       buttRemove.setOpaque(true);
889       buttRemove.setText("X");
890 
891       Font font = getFont().deriveFont(Font.BOLD);
892       buttRemove.setFont(font);
893       buttRemove.setToolTipText("REMOVE");
894       buttRemove.setHorizontalAlignment(SwingConstants.CENTER);
895 
896       buttView.setOpaque(true);
897       buttView.setFont(font);
898       buttView.setHorizontalAlignment(SwingConstants.CENTER);
899 
900       symbol.setOpaque(true);
901       symbol.setFont(font);
902       symbol.setHorizontalAlignment(SwingConstants.CENTER);
903     }
904 
905 
getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, final int row, final int column)906     public Component getTableCellRendererComponent(
907         JTable table,
908         Object value,
909         boolean isSelected,
910         boolean hasFocus,
911         final int row,
912         final int column)
913     {
914       Component c = null;
915       String text = null;
916       if(value != null)
917         text = (String)value;
918       Dimension dim;
919 
920       TableColumn tableCol;
921       if(column == getColumnIndex(GENE_COL))
922       {
923         String geneStr[] = text.split(":");
924         if(geneStr.length > 1)
925           gene.setText(geneStr[1]);
926 
927         if(isSelected)
928         {
929           gene.setForeground(fgLinkColor);
930           gene.setBackground(table.getSelectionBackground());
931         }
932         else
933         {
934           gene.setForeground(fgLinkColor);
935           gene.setBackground(UIManager.getColor("Button.background"));
936         }
937 
938         c = gene;
939       }
940       else if(column == getColumnIndex(ORGANISM_COL))
941       {
942         organism.setText(text);
943         c = organism;
944       }
945       else if(column == getColumnIndex(PRODUCT_COL))
946       {
947         product.setText(text);
948         c = product;
949       }
950       else if(column == getColumnIndex(LINK_COL))
951       {
952         link.setText(text);
953         c = link;
954       }
955       else if(column == getColumnIndex(CLUSTER_NAME_COL))
956       {
957         clusterName.setText(text);
958 
959         tableCol = table.getColumnModel().getColumn(column);
960         clusterName.setSize(tableCol.getWidth(), table
961             .getRowHeight(row));
962 
963         dim = clusterName.getPreferredSize();
964         minHeight = Math.max(minHeight, dim.height);
965         c = clusterName;
966       }
967       else if(column == getColumnIndex(MATCH_NAME_COL))
968       {
969         matchName.setText(text);
970         c = matchName;
971       }
972       else if(column == getColumnIndex(ROW_TYPE_HIDE_COL))
973       {
974         type.setText(text);
975         c = type;
976       }
977       else if(column == getColumnIndex(PROGRAM_COL))
978       {
979         program.setText(text);
980         c = program;
981       }
982       else if(column == getColumnIndex(ROW_TYPE_COL))
983       {
984         symbol.setText(text);
985 
986         if(text.equals("O"))
987           symbol.setForeground(fgColor);
988         else
989           symbol.setForeground(Color.GREEN);
990         tableCol = table.getColumnModel().getColumn(column);
991         symbol.setSize(tableCol.getWidth(), table
992             .getRowHeight(row));
993 
994         dim = symbol.getPreferredSize();
995         minHeight = Math.max(minHeight, dim.height);
996         c = symbol;
997       }
998       else if(column == getColumnIndex(VIEW_BUTTON_COL))
999       {
1000         if(isSelected)
1001         {
1002           buttView.setForeground(fgColor);
1003           buttView.setBackground(table.getSelectionBackground());
1004         }
1005         else
1006         {
1007           buttView.setForeground(fgColor);
1008           buttView.setBackground(UIManager.getColor("Button.background"));
1009         }
1010         c = buttView;
1011       }
1012       else if(column == getColumnIndex(REMOVE_BUTTON_COL))
1013       {
1014         if(isSelected)
1015         {
1016           buttRemove.setForeground(fgColor);
1017           buttRemove.setBackground(table.getSelectionBackground());
1018         }
1019         else
1020         {
1021           buttRemove.setForeground(fgColor);
1022           buttRemove.setBackground(UIManager.getColor("Button.background"));
1023         }
1024         c = buttRemove;
1025       }
1026       else
1027       {
1028         throw new RuntimeException("invalid column! " + column +
1029                                    " " + text);
1030       }
1031 
1032       // adjust row height for columns with multiple lines
1033       if(column < 3)
1034       {
1035         if(table.getRowHeight(row) < minHeight)
1036           table.setRowHeight(row, minHeight);
1037 
1038         minHeight = -1;
1039       }
1040 
1041       // highlight on selection
1042       if(isSelected)
1043         c.setBackground(table.getSelectionBackground());
1044       else
1045         c.setBackground(Color.white);
1046 
1047       return c;
1048     }
1049   }
1050 
1051   public class OrthoParalogValueComparator implements Comparator
1052   {
compare(Object o1, Object o2)1053     public int compare(Object o1, Object o2)
1054     {
1055       final String value1 = (String)o1;
1056       final String value2 = (String)o2;
1057 
1058       StringVector values1 = StringVector.getStrings((String)value1, ";");
1059       String rank1 = ArtemisUtils.getString(values1, "rank");
1060       if(!rank1.equals(""))
1061       {
1062         if(rank1.startsWith("rank=") || rank1.startsWith("rank "))
1063           rank1 = rank1.substring(5);
1064       }
1065       else
1066         rank1 = "0";
1067 
1068       StringVector values2 = StringVector.getStrings((String)value2, ";");
1069       String rank2 = ArtemisUtils.getString(values2, "rank");
1070       if(!rank2.equals(""))
1071       {
1072         if(rank2.startsWith("rank=") || rank2.startsWith("rank "))
1073           rank2 = rank2.substring(5);
1074       }
1075       else
1076         rank2 = "0";
1077 
1078 
1079       return (new Integer(rank1)).compareTo(new Integer(rank2));
1080     }
1081   }
1082 
1083   public class FeatureNamePredicate implements FeaturePredicate
1084   {
1085     private String uniqueName;
1086 
FeatureNamePredicate(final String uniqueName)1087     public FeatureNamePredicate(final String uniqueName)
1088     {
1089       this.uniqueName = uniqueName;
1090     }
1091 
testPredicate(Feature feature)1092     public boolean testPredicate(Feature feature)
1093     {
1094       try
1095       {
1096         String featureId = (String)feature.getQualifierByName("ID").getValues().get(0);
1097         if(featureId.equals(uniqueName))
1098           return true;
1099       }
1100       catch(InvalidRelationException e){}
1101 
1102       return false;
1103     }
1104 
1105   }
1106 }