Skip to content
Snippets Groups Projects
TransferAnnotationTool.java 31 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* TransferAnnotationTool.java
     *
    
    tjc's avatar
    tjc committed
     *
     * This file is part of Artemis
     *
    
     * Copyright (C) 2009  Genome Research Limited
    
    tjc's avatar
    tjc committed
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; either version 2
     * 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 General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     *
     */
    
    package uk.ac.sanger.artemis.components;
    
    
    import java.awt.BorderLayout;
    
    import java.awt.Cursor;
    
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    
    tjc's avatar
    tjc committed
    import java.awt.Font;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    
    import java.awt.Insets;
    
    tjc's avatar
    tjc committed
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    import java.util.Enumeration;
    import java.util.Hashtable;
    
    tjc's avatar
    tjc committed
    import java.util.List;
    
    tjc's avatar
    tjc committed
    import java.util.Vector;
    
    
    import javax.swing.Box;
    
    tjc's avatar
    tjc committed
    import javax.swing.JButton;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    
    import javax.swing.JOptionPane;
    
    tjc's avatar
    tjc committed
    import javax.swing.JPanel;
    
    import javax.swing.JScrollPane;
    
    import javax.swing.SwingConstants;
    
    import javax.swing.border.EtchedBorder;
    import javax.swing.border.TitledBorder;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.Entry;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.EntryGroup;
    import uk.ac.sanger.artemis.Feature;
    import uk.ac.sanger.artemis.FeaturePredicate;
    import uk.ac.sanger.artemis.FeatureVector;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.SimpleEntryGroup;
    import uk.ac.sanger.artemis.chado.ChadoTransactionManager;
    import uk.ac.sanger.artemis.components.genebuilder.GeneEdit;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    
    import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.DatabaseDocumentEntry;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.GFFStreamFeature;
    
    import uk.ac.sanger.artemis.io.InvalidRelationException;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.PartialSequence;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.Qualifier;
    import uk.ac.sanger.artemis.io.QualifierVector;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.DatabaseDocument;
    
    import uk.ac.sanger.artemis.util.StringVector;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
    public class TransferAnnotationTool extends JFrame
    
    tjc's avatar
    tjc committed
    {
      private static final long serialVersionUID = 1L;
      private static String[] NON_TRANSFERABLE_QUALIFIERS =
      {
        "ID",
        "feature_id",
        "Derives_from",
        "feature_relationship_rank",
        "Parent",
        "isObsolete",
    
        "isFminPartial",
        "isFmaxPartial",
    
    tjc's avatar
    tjc committed
        "timelastmodified",
    
    tjc's avatar
    tjc committed
        "cytoplasmic_polypeptide_region",
    
        "membrane_structure",
    
        "non_cytoplasm_location",
    
    tjc's avatar
    tjc committed
        "non_cytoplasmic_polypeptide_region",
    
    tjc's avatar
    tjc committed
        "orthologous_to",
        "paralogous_to",
    
    tjc's avatar
    tjc committed
        "pepstats_file",
    
        "PlasmoAP_score",
        "polypeptide_domain",
    
    tjc's avatar
    tjc committed
        "fasta_file",
    
    tjc's avatar
    tjc committed
        "blastp_file",
        "blastn_file",
        "systematic_id",
    
    tjc's avatar
    tjc committed
        "transmembrane_polypeptide_region",
    
    tjc's avatar
    tjc committed
        "previous_systematic_id"
    
    tjc's avatar
    tjc committed
      };
    
      private static org.apache.log4j.Logger logger4j = 
        org.apache.log4j.Logger.getLogger(TransferAnnotationTool.class);
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      protected static Color STEEL_BLUE = new Color(25, 25, 112);
    
      
      /**
       * Tool for transferring annotation from one feature to other feature(s)
       * @param feature
       * @param entryGroup
       * @param geneNames
       */
    
    tjc's avatar
    tjc committed
      public TransferAnnotationTool(final Feature feature, 
    
      		                        final EntryGroup entryGroup,
      		                        final List geneNames)
    
    tjc's avatar
    tjc committed
      {
        super("Transfer Annotation Tool :: "
            + feature.getIDString());
    
    
        FlowLayout flow = new FlowLayout(FlowLayout.LEFT);
        JPanel panel = new JPanel(flow);
        JPanel pane = new JPanel(new GridBagLayout());
        JScrollPane jsp = new JScrollPane(panel);
    
        panel.setBackground(Color.white);
        pane.setBackground(Color.white);
    
        panel.add(pane);
        
        JPanel framePanel = (JPanel)getContentPane();
        framePanel.add(jsp, BorderLayout.CENTER);
        framePanel.setPreferredSize(new Dimension(600,600));
        
    
        final Vector geneNameCheckBoxes = new Vector();
    
        final Vector qualifierPanels = new Vector();
    
        addMainPanel(feature, pane, qualifierPanels, 
    
        addBottomButtons(qualifierPanels, geneNameCheckBoxes, 
                         framePanel, entryGroup);
    
        
        pack();
        setVisible(true);
      }
      
      /**
       * Construct the panel for setting up the gene list and the
       * list of qualifiers to transfer.
       * @param feature
       * @param pane
       * @param qualifierCheckBoxes
       * @param geneNameCheckBoxes
       * @param geneNames
       */
      private void addMainPanel(final Feature feature, 
                                final JPanel pane, 
    
                                final Vector geneNameCheckBoxes,
                                final List geneNames)
      {
    
    tjc's avatar
    tjc committed
        GridBagConstraints c = new GridBagConstraints();
        int nrows = 0;
    
    
        c.anchor = GridBagConstraints.NORTHWEST;
        c.gridx = 2;
    
    tjc's avatar
    tjc committed
        c.gridy = 0;
    
    tjc's avatar
    tjc committed
        c.ipadx = 50;
    
        JLabel geneLabel = new JLabel("Qualifier(s)");
    
    tjc's avatar
    tjc committed
        geneLabel.setFont(geneLabel.getFont().deriveFont(Font.BOLD));
        pane.add(geneLabel, c);
    
        c.gridx = 0;
    
    tjc's avatar
    tjc committed
        JLabel label = new JLabel("Gene List");
        label.setFont(label.getFont().deriveFont(Font.BOLD));
        pane.add(label, c);
    
    
        c.gridy = ++nrows;
    
    tjc's avatar
    tjc committed
        c.gridy = ++nrows;
        c.anchor = GridBagConstraints.WEST;
    
        
        addQualifierPanel(feature, qualifierPanels, c, nrows, pane);
        nrows+=2;
        
        if(feature.getEmblFeature() instanceof GFFStreamFeature)
    
    tjc's avatar
    tjc committed
        {
    
          GFFStreamFeature gffFeature = 
            ((GFFStreamFeature) feature.getEmblFeature());
          if (gffFeature.getChadoGene() != null)
          {
            String id = GeneUtils.getUniqueName(gffFeature);
            ChadoCanonicalGene chadoGene = gffFeature.getChadoGene();
            Feature gene = (Feature) chadoGene.getGene().getUserData();
            
            if(!id.equals( GeneUtils.getUniqueName(((GFFStreamFeature)chadoGene.getGene())) ))
             addQualifierPanel(gene, qualifierPanels, c, nrows, pane);
            
            nrows+=2;
           
            String transcriptName = 
              chadoGene.getTranscriptFromName(GeneUtils.getUniqueName(gffFeature));
            
            if(transcriptName != null)
            {
              GFFStreamFeature transcript = 
                     (GFFStreamFeature) chadoGene.getFeatureFromId(transcriptName);
              addQualifierPanel((Feature)transcript.getUserData(), 
                  qualifierPanels, c, nrows, pane);
              nrows+=2;
              
              Set children = chadoGene.getChildren(transcript);
              Iterator it = children.iterator();
              
              while(it.hasNext())
              {
                GFFStreamFeature kid = (GFFStreamFeature)it.next();
                
                if(id.equals( GeneUtils.getUniqueName(((GFFStreamFeature)kid)) ))
                  continue;
                addQualifierPanel((Feature)kid.getUserData(), qualifierPanels,
                                  c, nrows, pane);
                nrows+=2;
              }
            }
          }
    
    tjc's avatar
    tjc committed
        }
    
        c.gridx = 0;
        c.gridy = 2;
    
    tjc's avatar
    tjc committed
        c.gridheight = nrows;
        c.fill = GridBagConstraints.BOTH;
    
    
        final Box geneNameBox = Box.createVerticalBox();
        pane.add(geneNameBox, c);
    
    tjc's avatar
    tjc committed
        
        if(geneNames != null)
        {
    
          for(int i = 0; i < geneNames.size(); i++)
          {
            JCheckBox cb = new JCheckBox((String) geneNames.get(i),true);
            geneNameBox.add(cb);
            geneNameCheckBoxes.add(cb);
          }
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
    
    
        c.gridy = 1;
    
    tjc's avatar
    tjc committed
        c.gridheight = 1;
        c.fill = GridBagConstraints.NONE;
    
        c.gridx = 2;
        final JButton toggle = new JButton("Toggle");
    
    tjc's avatar
    tjc committed
        toggle.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
            for(int i=0; i<qualifierPanels.size(); i++)
    
    tjc's avatar
    tjc committed
            {
    
              QualifierPanel qP = (QualifierPanel)qualifierPanels.get(i);
              Enumeration enumQualifiers = qP.getQualifierCheckBoxes().keys();
              while(enumQualifiers.hasMoreElements())
              {
                JCheckBox cb = (JCheckBox) enumQualifiers.nextElement();
                cb.setSelected(!cb.isSelected());
              }
    
    tjc's avatar
    tjc committed
            }
          }
        });
        pane.add(toggle, c);
    
        final JButton toggleGeneList = new JButton("Toggle");
        toggleGeneList.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            for(int i = 0; i < geneNameCheckBoxes.size(); i++)
            {
              JCheckBox cb = (JCheckBox) geneNameCheckBoxes.get(i);
              cb.setSelected(!cb.isSelected());
            }
          }
        });
    
        final JButton addGenes = new JButton("Add");
        addGenes.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            JTextArea geneNameTextArea = new JTextArea();
            geneNameTextArea.setEditable(true);
            JScrollPane jsp = new JScrollPane(geneNameTextArea);
            
            int res = JOptionPane.showConfirmDialog(TransferAnnotationTool.this,
    
                     jsp, "Paste Feature Names to Add", 
    
                     JOptionPane.OK_CANCEL_OPTION);
            if(res == JOptionPane.CANCEL_OPTION)
              return;
            
            String geneNames[] = geneNameTextArea.getText().split("\\s");
            for(int i=0;i<geneNames.length; i++)
            {
              if(geneNames[i] == null || geneNames[i].equals(""))
                continue;
               JCheckBox cb = new JCheckBox(geneNames[i],true);
               geneNameBox.add(cb);
               geneNameCheckBoxes.add(cb);
            }
            pane.revalidate();
          }
        });
        xBox.add(addGenes); 
        c.gridx = 0;
        pane.add(xBox, c);  
      }
    
      
      /**
       * Add a panel to display a given features qualifiers.
       * @param f
       * @param qualifierPanels
       * @param c
       * @param nrows
       * @param pane
       */
      private void addQualifierPanel(Feature f,
                                     Vector qualifierPanels,
                                     GridBagConstraints c,
                                     int nrows,
                                     JPanel pane)
      {
        QualifierPanel qPanel = new QualifierPanel(f,f.getKey().getKeyString());
        if(qPanel.nrows == 0)
          return;
    
        c.fill = GridBagConstraints.HORIZONTAL;
        c.anchor = GridBagConstraints.WEST;
        c.weightx = 100;
        qualifierPanels.add(qPanel);
        c.gridy = ++nrows;
    
        JLabel l = new JLabel(f.getIDString());
        l.setFont(l.getFont().deriveFont(Font.BOLD));
        l.setForeground(STEEL_BLUE);
        pane.add(l, c);
        
        c.gridy = ++nrows;
        pane.add(qPanel, c);
        c.weightx = 0.d;
      }
    
    tjc's avatar
    tjc committed
    
    
    
      /**
       * Add panel for the transfer and close button.
       * @param qualifierCheckBoxes
       * @param geneNameCheckBoxes
       * @param framePanel
       * @param feature
       * @param entryGroup
       */
    
      private void addBottomButtons(final Vector qualifierPanels,
    
    tjc's avatar
    tjc committed
        final JCheckBox sameKeyCheckBox = new JCheckBox("Add to feature of same key", true);
    
        final JCheckBox overwriteCheckBox = new JCheckBox("Overwrite", false);
        overwriteCheckBox.setToolTipText("overwrite rather than append values");
        
    
        Box buttonBox = Box.createHorizontalBox();
    
    tjc's avatar
    tjc committed
        final JButton transfer = new JButton(">>TRANSFER");
    
        transfer.setToolTipText("transfer annotation");
    
    tjc's avatar
    tjc committed
        transfer.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
            if(overwriteCheckBox.isSelected())
            {
              int res = JOptionPane.showConfirmDialog(TransferAnnotationTool.this, 
                  "Overwrite selected annotation?", 
                  "Overwrite", JOptionPane.OK_CANCEL_OPTION);
              if(res == JOptionPane.CANCEL_OPTION)
                return;
            }
            
    
    tjc's avatar
    tjc committed
            setCursor(new Cursor(Cursor.WAIT_CURSOR));
    
            StringBuffer buff = new StringBuffer();
            StringBuffer summary = new StringBuffer();
    
            for(int i = 0; i < qualifierPanels.size(); i++)
            {
              QualifierPanel qP = (QualifierPanel) qualifierPanels.get(i);
    
    tjc's avatar
    tjc committed
              int res = transferAnnotation(qP.getQualifierCheckBoxes(), 
    
                  geneNameCheckBoxes, qP.getFeature(), entryGroup, 
                  sameKeyCheckBox.isSelected(),
    
                  overwriteCheckBox.isSelected(), buff, summary);
    
    tjc's avatar
    tjc committed
              if(res == -1)
                break;
    
            
            if(buff.length() > 0)
              logger4j.debug("TRANSFERRED ANNOTATION SUMMARY:\n"+buff.toString());
    
    tjc's avatar
    tjc committed
            setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    
            
            if(summary.length()>0)
            {
              final JTextArea list = new JTextArea(summary.toString());
              final JScrollPane jsp = new JScrollPane(list);
              jsp.setPreferredSize(new Dimension(300,200));
              JOptionPane.showMessageDialog(
                  TransferAnnotationTool.this, jsp, 
                  "Summary of Genes Changed",
                  JOptionPane.INFORMATION_MESSAGE);
            }
    
    tjc's avatar
    tjc committed
          }
        });
    
        Box yBox = Box.createVerticalBox();
        yBox.add(transfer);
        yBox.add(sameKeyCheckBox);
    
        buttonBox.add(yBox);
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        final JButton close = new JButton("CLOSE");
        close.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            dispose();
          }
        });
    
        yBox = Box.createVerticalBox();
        yBox.add(close);
        yBox.add(Box.createVerticalGlue());
        buttonBox.add(yBox);
        buttonBox.add(Box.createHorizontalGlue());
        framePanel.add(buttonBox, BorderLayout.SOUTH);
    
    tjc's avatar
    tjc committed
      }
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      /**
       * Returns true if this qualifier is non-transferable
       * @param qualifierName
       * @return
       */
    
    tjc's avatar
    tjc committed
      protected static boolean isNonTransferable(String qualifierName)
    
    tjc's avatar
    tjc committed
      {
        for(int i=0; i<NON_TRANSFERABLE_QUALIFIERS.length; i++)
        {
          if(NON_TRANSFERABLE_QUALIFIERS[i].equals(qualifierName))
            return true;
        }
        return false;
      }
      
      /**
       * Transfer selected qualifiers to the list of features defined
    
    tjc's avatar
    tjc committed
       * @param qualifierCheckBoxes - list of qualifier check boxes
       * @param geneNameTextArea - text with a list of feature names to transfer to
       * @param feature - feature to copy from 
       * @param entryGroup
    
    tjc's avatar
    tjc committed
       */
    
    tjc's avatar
    tjc committed
      protected static int transferAnnotation(
                                     final Hashtable qualifierCheckBoxes, 
    
    tjc's avatar
    tjc committed
      		                         final Vector geneNameCheckBoxes,
      		                         final Feature orginatingFeature,
      		                         final EntryGroup entryGroup,
      		                         final boolean sameKey,
    
      		                         final boolean overwrite,
      		                         final StringBuffer buff,
      		                         final StringBuffer genesUpdated)
    
    tjc's avatar
    tjc committed
      {
        // transfer selected annotation to genes
    
        final QualifierVector qualifiers = orginatingFeature.getQualifiers();
        final QualifierVector qualifiersToTransfer = new QualifierVector();
        
        Enumeration enumQualifiers = qualifierCheckBoxes.keys();
        while(enumQualifiers.hasMoreElements())
    
    tjc's avatar
    tjc committed
        {
    
          JCheckBox cb = (JCheckBox) enumQualifiers.nextElement();
          if (cb.isSelected())
          {
            Vector qualifierValuesCheckBox = (Vector)qualifierCheckBoxes.get(cb);
            StringVector values = qualifiers.getQualifierByName(cb.getText()).getValues();
            StringVector valuesToTransfer = new StringVector(values);
            
            logger4j.debug("TRANSFER "+cb.getText());
            for(int i=0; i<qualifierValuesCheckBox.size(); i++)
            {
              JCheckBox valuesCb = (JCheckBox) qualifierValuesCheckBox.get(i);
              if(!valuesCb.isSelected())
              {
                valuesToTransfer.remove(valuesCb.getText());
                logger4j.debug("NOT TRANSFERING "+valuesCb.getText());
              }
            }
            
            if(valuesToTransfer.size() < 1)
              continue;
            qualifiersToTransfer.addElement(new Qualifier(cb.getText(), valuesToTransfer));
          }
    
    tjc's avatar
    tjc committed
        }
    
    
        int count = 0;
      	for(int i =0; i<geneNameCheckBoxes.size(); i++)
      	{
      	  if( ((JCheckBox)geneNameCheckBoxes.get(i)).isSelected() )
      	    count++;
      	}
    
    tjc's avatar
    tjc committed
      	
    
      	if(count < 1)
      	{
    
    tjc's avatar
    tjc committed
      	  JOptionPane.showMessageDialog(null, 
    
            "No genes selected.", 
            "Warning", JOptionPane.WARNING_MESSAGE);
    
    tjc's avatar
    tjc committed
      	  return -1;
    
    tjc's avatar
    tjc committed
      	
    
      	String geneNames[] = new String[count];
      	count = 0;
      	for(int i =0; i<geneNameCheckBoxes.size(); i++)
        {
      	  JCheckBox cb = (JCheckBox)geneNameCheckBoxes.get(i);
          if( cb.isSelected() )
          {
            geneNames[count] = cb.getText();
            logger4j.debug("TRANSFER ANNOTATION TO "+geneNames[count]);
            count++;
          }
        }
    
    tjc's avatar
    tjc committed
    
      	final String key = orginatingFeature.getKey().getKeyString();
    
    tjc's avatar
    tjc committed
      	final FeatureVector features = entryGroup.getAllFeatures();
    
    
    tjc's avatar
    tjc committed
      	// transfer selected annotation
      	entryGroup.getActionController().startAction();
    
      	geneNames = transfer(features, qualifiersToTransfer, key, sameKey, overwrite, 
      			             GeneUtils.isDatabaseEntry(entryGroup), geneNames, genesUpdated);
    
    tjc's avatar
    tjc committed
      	entryGroup.getActionController().endAction();
      	
      	//
      	// Commit changes to genes not in Artemis but in the database
      	//
    
        Vector genesNotFound = null;
    
    tjc's avatar
    tjc committed
        if (orginatingFeature.getEntry().getEMBLEntry() instanceof DatabaseDocumentEntry)
    
    tjc's avatar
    tjc committed
          DatabaseDocumentEntry db_entry =
            (DatabaseDocumentEntry) orginatingFeature.getEntry().getEMBLEntry();
          DatabaseDocument doc = (DatabaseDocument) db_entry.getDocument();
    
    tjc's avatar
    tjc committed
          for (int i = 0; i < geneNames.length; i++)
    
    tjc's avatar
    tjc committed
            DatabaseDocumentEntry newDbEntry = GeneEdit.makeGeneEntry(null,
                geneNames[i], doc, null);
    
    tjc's avatar
    tjc committed
            if (newDbEntry == null)
            {
              if (genesNotFound == null)
                genesNotFound = new Vector();
              genesNotFound.add(geneNames[i]);
              continue;
            }
    
    tjc's avatar
    tjc committed
            char[] c = new char[1];
            PartialSequence ps = new PartialSequence(c, 100, 0, null, null);
            newDbEntry.setPartialSequence(ps);
            Entry entry = null;
            try
            {
              entry = new Entry(newDbEntry);
            }
            catch (Exception e)
            {
              e.printStackTrace();
            }
    
            SimpleEntryGroup entry_group = new SimpleEntryGroup();
            entry_group.addElement(entry);
    
    tjc's avatar
    tjc committed
            ChadoTransactionManager ctm = new ChadoTransactionManager();
            entry_group.addFeatureChangeListener(ctm);
            entry_group.addEntryChangeListener(ctm);
            ctm.setEntryGroup(entry_group);
    
    tjc's avatar
    tjc committed
            transfer(entry.getAllFeatures(), qualifiersToTransfer, key, sameKey,
    
                overwrite, true, geneNames, genesUpdated);
            
            for(int j=0; j<ctm.getTransactionCount(); j++)
              buff.append(ctm.getTransactionAt(j).getLogComment()+"\n");
    
    tjc's avatar
    tjc committed
            ChadoTransactionManager.commit((DatabaseDocument) newDbEntry
                .getDocument(), false, ctm);
    
    tjc's avatar
    tjc committed
            entry_group.removeFeatureChangeListener(ctm);
            entry_group.removeEntryChangeListener(ctm);
            // if(newDbEntry != null)
            // GeneEdit.showGeneEditor(null, geneNames[i], newDbEntry);
          }
    
      	
      	if(genesNotFound != null)
    
    tjc's avatar
    tjc committed
      		JOptionPane.showMessageDialog(null, 
    
      				"Gene(s) Not Found:\n"+genesNotFound.toString(), 
      				"Gene(s) Not Found", JOptionPane.WARNING_MESSAGE);
    
    tjc's avatar
    tjc committed
      	return 0;
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * 
       * @param features
       * @param qualifiersToTransfer
       * @param key
       * @param sameKey
       * @param isDatabaseEntry
       * @param geneNames
       * @return
       */
    
    tjc's avatar
    tjc committed
      private static String[] transfer(final FeatureVector features,
    
                                final QualifierVector qualifiersToTransfer, 
                                final String key,
    
                                final boolean sameKey,
                                final boolean overwrite,
    
                                final boolean isDatabaseEntry, 
    
                                String[] geneNames,
                                final StringBuffer genesUpdated)
    
      {
        final TransferFeaturePredicate predicate = new TransferFeaturePredicate(
            key, sameKey, isDatabaseEntry, geneNames);
    
    tjc's avatar
    tjc committed
    
    
        for (int i = 0; i < features.size(); i++)
        {
          Feature thisFeature = features.elementAt(i);
          if (predicate.testPredicate(thisFeature))
          {
    
            StringBuffer qualifierBuffer = new StringBuffer();
    
            for (int j = 0; j < qualifiersToTransfer.size(); j++)
            {
              Qualifier newQualifier = (Qualifier) qualifiersToTransfer.elementAt(j);
    
              String qualifierName = newQualifier.getName();
    
                  thisFeature.setQualifier(newQualifier);
    
                  qualifierBuffer.append("  "+qualifierName+" (overwritten)\n"+
                      parseStringVector(newQualifier.getValues()));
                }
    
                else
                {
                  final StringVector oldValues;
                  if (thisFeature.getQualifierByName(newQualifier.getName()) == null)
                    oldValues = null;
                  else
                    oldValues = thisFeature.getQualifierByName(
                        newQualifier.getName()).getValues();
    
                  final Qualifier newQualifierTmp = getQualifierWithoutDuplicateValues(
                      newQualifier, oldValues);
                  if (newQualifierTmp == null)
                    continue;
                  thisFeature.addQualifierValues(newQualifierTmp);
    
                  qualifierBuffer.append("  "+qualifierName+" (added)\n"+
                      parseStringVector(newQualifier.getValues()));
    
              }
              catch (Exception e1)
              {
                e1.printStackTrace();
              }
            }
            geneNames = removeArrayElement(geneNames, predicate.getGeneName());
    
            if(qualifierBuffer.length() > 0)
              genesUpdated.append(thisFeature.getSystematicName()+
                                  " ("+key+")\n"+qualifierBuffer);
    
      /**
       * Get a StringBuffer representation of the values in a StringVector
       * @param v
       * @return
       */
      private static StringBuffer parseStringVector(final StringVector v)
      {
        StringBuffer buff = new StringBuffer();
        for(int i=0; i<v.size(); i++)
          buff.append("    "+v.elementAt(i)+"\n");
        return buff;
      }
      
    
      /**
       * Return a qualifier copy of the qualifier provided that does not contain
       * any of the values in the StringVector.
       * @param newQualifier
       * @param oldValues
       * @return
       * @throws InvalidRelationException
       */
    
    tjc's avatar
    tjc committed
      private static Qualifier getQualifierWithoutDuplicateValues( 
    
          final Qualifier qualifier,
          final StringVector values) throws InvalidRelationException
      {
        final Qualifier newQualifier;
        if (values == null || values.size() < 1)
          newQualifier = qualifier;
        else
        {
          StringVector newValues =  qualifier.getValues();
          StringVector valuesToAdd = new StringVector();
          for (int k = 0; k < newValues.size(); k++)
          {
            if(!values.contains(newValues.get(k)))
              valuesToAdd.add(newValues.get(k));
          }
    
          if(valuesToAdd.size() == 0)
            return null;
          newQualifier = new Qualifier(qualifier.getName(), valuesToAdd);
        }
        return newQualifier;
      }
    
    tjc's avatar
    tjc committed
      
      /**
       * Remove a string from an array of strings. If the string appears multiple 
       * times in the array this method will delete all occurrences.
       * @param strArr
       * @param str
       * @return
       */
    
    tjc's avatar
    tjc committed
      private static String[] removeArrayElement(final String strArr[], final String str)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        if(strArr.length == 1)
          return strArr;
    
    tjc's avatar
    tjc committed
        String[] newarray = new String[strArr.length - 1];
        int count = 0;
        for (int i = 0; i < strArr.length; i++)
        {
          if (strArr[i].equals(str))
            continue;
    
          // not found str return original array
          if (count >= newarray.length)
            return strArr;
          newarray[count] = strArr[i];
          count++;
        }
    
        if (count < newarray.length)
        {
          String[] tmparray = new String[count];
          System.arraycopy(newarray, 0, tmparray, 0, count);
          newarray = tmparray;
        }
    
    
    tjc's avatar
    tjc committed
        return newarray;
      }
       
    
    tjc's avatar
    tjc committed
    
     
    }
    
    class QualifierPanel extends JPanel
    {
      private Hashtable qualifierCheckBoxes = new Hashtable();
      private Feature feature;
      protected int nrows = 0;
      
      public QualifierPanel(Feature feature, String title)
    
    tjc's avatar
    tjc committed
        super(new GridBagLayout());
        
        this.feature = feature;
        
        TitledBorder titleBorder = BorderFactory.createTitledBorder(
            BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), title);
        titleBorder.setTitleJustification(TitledBorder.LEFT);
        titleBorder.setTitleColor(TransferAnnotationTool.STEEL_BLUE);
        setBorder(titleBorder);
        
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.WEST;
        c.ipadx = 0;
        final QualifierVector qualifiers = feature.getQualifiers();
    
    tjc's avatar
    tjc committed
        for(int i = 0; i < qualifiers.size(); i++)
    
    tjc's avatar
    tjc committed
          nrows = 
            addQualifierComponents((Qualifier) qualifiers.get(i), 
                                  qualifierCheckBoxes, c, nrows);
    
    tjc's avatar
    tjc committed
        setMinimumSize(new Dimension(
            titleBorder.getMinimumSize(this).width, 
                       getMinimumSize().height));
      }
      
      /**
       * Add a qualifier to the list of transferable annotation
       * @param pane
       * @param qualifier
       * @param qualifierCheckBoxes
       * @param c
       * @param nrows
       * @return
       */
      private int addQualifierComponents(final Qualifier qualifier, 
                                         final Hashtable qualifierCheckBoxes,
                                         final GridBagConstraints c,
                                         int nrows)
      {
        if(TransferAnnotationTool.isNonTransferable(qualifier.getName()))
    
    tjc's avatar
    tjc committed
        final JCheckBox qualifierNameCheckBox = new JCheckBox(qualifier.getName(), false);
        c.gridx = 1;
        c.fill = GridBagConstraints.NONE;
        c.weightx = 0.d;
        Box qualifierValueBox = Box.createVerticalBox();
        
        JButton detailsShowHide = new JButton("+");
        final Vector qualifierValuesCheckBox = setExpanderButton(detailsShowHide,
            qualifier, qualifierValueBox, qualifierNameCheckBox);
        
        qualifierNameCheckBox.addItemListener(new ItemListener()
    
    tjc's avatar
    tjc committed
          public void itemStateChanged(ItemEvent e)
    
            if(qualifierNameCheckBox.isSelected())
            {
              for(int i=0; i<qualifierValuesCheckBox.size(); i++)
              {
                JCheckBox cb = (JCheckBox) qualifierValuesCheckBox.get(i);
                if(cb.isSelected())
                  return;
              }
            }
            
    
    tjc's avatar
    tjc committed
            for(int i=0; i<qualifierValuesCheckBox.size(); i++)
    
    tjc's avatar
    tjc committed
              JCheckBox cb = (JCheckBox) qualifierValuesCheckBox.get(i);
              cb.setSelected(qualifierNameCheckBox.isSelected());
    
    tjc's avatar
    tjc committed
          }        
        });
        add(detailsShowHide, c);
    
    tjc's avatar
    tjc committed
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 100; 
        c.gridx = 2;
    
        add(qualifierNameCheckBox, c);
        qualifierCheckBoxes.put(qualifierNameCheckBox, qualifierValuesCheckBox);
        c.gridy = ++nrows;
        add(qualifierValueBox, c);
        c.gridy = ++nrows;
        return nrows;
    
    tjc's avatar
    tjc committed
      /**
    
    tjc's avatar
    tjc committed
       * Set up the expander button to display qualifier values.
       * @param butt - expander button
       * @param qualifier - the qualifer that is being displayed
       * @param qualifierValueBox - Box containing the values
       * @param qualifierNameCheckBox - JCheckBox for the given qualifier
       * @param pane
       * @return
    
    tjc's avatar
    tjc committed
       */
    
    tjc's avatar
    tjc committed
      private Vector setExpanderButton(final JButton butt,
                                       final Qualifier qualifier, 
                                       final Box qualifierValueBox,
                                       final JCheckBox qualifierNameCheckBox)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        butt.setMargin(new Insets(0, 0, 0, 0));
        butt.setHorizontalAlignment(SwingConstants.RIGHT);
        butt.setHorizontalTextPosition(SwingConstants.RIGHT);
        butt.setBorderPainted(false);
        butt.setFont(butt.getFont().deriveFont(Font.BOLD));
        butt.setForeground(TransferAnnotationTool.STEEL_BLUE);
        
        butt.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          public void actionPerformed(ActionEvent e)
          {
            if (butt.getText().equals("+"))
              butt.setText("-");
            else
              butt.setText("+");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            qualifierValueBox.setVisible(butt.getText().equals("-"));
            revalidate();
          }
        });
    
        // set-up qualifier values list
        qualifierValueBox.setVisible(false);
        Vector qualifierValuesCheckBox = new Vector();
        StringVector values = qualifier.getValues();
        for (int i = 0; i < values.size(); i++)
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          JCheckBox cb = new JCheckBox((String) values.get(i),
              qualifierNameCheckBox.isSelected());
          cb.setFont(cb.getFont().deriveFont(Font.ITALIC));
          qualifierValueBox.add(cb);
          qualifierValuesCheckBox.add(cb);
        }
        return qualifierValuesCheckBox;
      }
      
      protected Hashtable getQualifierCheckBoxes()
      {
        return qualifierCheckBoxes;
      }
      
      protected Feature getFeature()
      {
        return feature;
      }
    }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
    /**
     * Test if the feature is nominated to have annotation transferred
     * to it. For genes in a chado database it looks at the gene name
     * and transcript name.
     */
    class TransferFeaturePredicate implements FeaturePredicate
    {
      private String geneName;
      private String key;
      private boolean sameKey;
      private boolean isDatabaseEntry;
      private String[] geneNames;
    
      public TransferFeaturePredicate(final String key, 
                                      final boolean sameKey,
                                      final boolean isDatabaseEntry, 
                                      final String[] geneNames)
      {
        this.key = key;
        this.sameKey = sameKey;
        this.isDatabaseEntry = isDatabaseEntry;
        this.geneNames = geneNames;
      }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
      public boolean testPredicate(Feature targetFeature)
      {
        String targetKey = targetFeature.getKey().getKeyString();
        if (sameKey && !targetKey.equals(key))
          return false;
    
        Vector chadoNames = null;
        if (isDatabaseEntry)
        {
          GFFStreamFeature gffFeature = 
            ((GFFStreamFeature) targetFeature.getEmblFeature());
          if (gffFeature.getChadoGene() != null)
    
    tjc's avatar
    tjc committed
          {
    
    tjc's avatar
    tjc committed
            chadoNames = new Vector();
            
            ChadoCanonicalGene chadoGene = gffFeature.getChadoGene();
            chadoNames.add(chadoGene.getGeneUniqueName());
            List transcripts = chadoGene.getTranscripts();
            for(int i=0;i<transcripts.size();i++)
    
    tjc's avatar
    tjc committed
            {
    
    tjc's avatar
    tjc committed
              GFFStreamFeature feature = (GFFStreamFeature) transcripts.get(i);
              chadoNames.add(GeneUtils.getUniqueName(feature));
    
    tjc's avatar
    tjc committed
            }
          }
        }
    
    
    tjc's avatar
    tjc committed
        String thisFeatureSystematicName = targetFeature.getSystematicName();
        for (int i = 0; i < geneNames.length; i++)
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          if(geneNames[i].equals(thisFeatureSystematicName) ||
             (chadoNames != null && chadoNames.contains(geneNames[i])))
          {
            geneName = geneNames[i];
            return true;
          }
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        return false;
      }
    
      protected String getGeneName()
      {
        return geneName;
    
    tjc's avatar
    tjc committed
      }
    }