Skip to content
Snippets Groups Projects
PropertiesPanel.java 34.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* GffPanel.java
     * This file is part of Artemis
     *
     * Copyright (C) 2007  Genome Research Limited
     *
     * 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.
     *
    
     * $Header: //tmp/pathsoft/artemis/uk/ac/sanger/artemis/components/genebuilder/gff/PropertiesPanel.java,v 1.11 2009-08-17 12:50:42 tjc Exp $
    
    tjc's avatar
    tjc committed
     */
    
    package uk.ac.sanger.artemis.components.genebuilder.gff;
    
    
    tjc's avatar
    tjc committed
    import java.awt.Color;
    
    tjc's avatar
    tjc committed
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    
    import java.awt.Font;
    
    tjc's avatar
    tjc committed
    import java.awt.FontMetrics;
    
    tjc's avatar
    tjc committed
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    
    tjc's avatar
    tjc committed
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import java.util.Iterator;
    import java.util.Set;
    
    tjc's avatar
    tjc committed
    import java.util.Vector;
    
    tjc's avatar
    tjc committed
    
    
    import javax.swing.BorderFactory;
    
    tjc's avatar
    tjc committed
    import javax.swing.Box;
    
    tjc's avatar
    tjc committed
    import javax.swing.ButtonGroup;
    
    tjc's avatar
    tjc committed
    import javax.swing.JCheckBox;
    
    tjc's avatar
    tjc committed
    import javax.swing.JLabel;
    
    tjc's avatar
    tjc committed
    import javax.swing.JOptionPane;
    
    tjc's avatar
    tjc committed
    import javax.swing.JPanel;
    
    tjc's avatar
    tjc committed
    import javax.swing.JRadioButton;
    
    tjc's avatar
    tjc committed
    import javax.swing.JTextField;
    
    tjc's avatar
    tjc committed
    import javax.swing.SwingConstants;
    
    tjc's avatar
    tjc committed
    import javax.swing.border.Border;
    
    tjc's avatar
    tjc committed
    
    import org.gmod.schema.cv.CvTerm;
    
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.FeatureChangeEvent;
    import uk.ac.sanger.artemis.FeatureChangeListener;
    import uk.ac.sanger.artemis.Feature;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.chado.ChadoTransactionManager;
    
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.JExtendedComboBox;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.editor.MultiLineToolTipUI;
    
    import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.GFFStreamFeature;
    
    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;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.StringVector;
    
    
    public class PropertiesPanel extends JPanel
    
    tjc's avatar
    tjc committed
                          implements FeatureChangeListener
    {
      private static final long serialVersionUID = 1L;
      private QualifierVector gffQualifiers;
    
    tjc's avatar
    tjc committed
      private JTextField uniquenameTextField;
    
      private JTextField primaryNameTextField;
    
      private JCheckBox obsoleteField;
    
    tjc's avatar
    tjc committed
      private JCheckBox partialField5prime;
      private JCheckBox partialField3prime;
      
    
    tjc's avatar
    tjc committed
      private Feature feature;
    
      /** controls if this panel is automatically closed or open */
    
      private boolean empty = true;
    
      /** track if feature isObsolete flag has changed */
    
      protected boolean obsoleteChanged = false;
      private boolean partialChanged = false;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
      private ButtonGroup phaseButtonGroup = null;
      
    
    tjc's avatar
    tjc committed
      private boolean showNames   = true;
    
    tjc's avatar
    tjc committed
      private boolean showParent  = true;
      private boolean showOptions = true;
      private boolean showTimeLastModified = true;
    
    tjc's avatar
    tjc committed
      
    
    tjc's avatar
    tjc committed
      static
      {
        MultiLineToolTipUI.initialize();
      }
      
    
      public PropertiesPanel(final Feature feature)
    
    tjc's avatar
    tjc committed
      {
    
    tjc's avatar
    tjc committed
        this(feature, true, true, true, true);
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      public PropertiesPanel(final Feature feature,
                             boolean showNames,
    
    tjc's avatar
    tjc committed
                             boolean showParent,
                             boolean showOptions, 
                             boolean showTimeLastModified)
    
    tjc's avatar
    tjc committed
      {
        super(new FlowLayout(FlowLayout.LEFT));
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        this.showNames   = showNames;
    
    tjc's avatar
    tjc committed
        this.showOptions = showOptions;
        this.showParent  = showParent;
        this.showTimeLastModified = showTimeLastModified;
        
        setBackground(Color.WHITE);
    
    tjc's avatar
    tjc committed
        updateFromFeature(feature);
    
        //makeBorder();
    
    tjc's avatar
    tjc committed
      }
      
      /**
       * Return true if this is a CV qualifier
       * @param qualifier
       * @return
       */
    
    tjc's avatar
    tjc committed
      public static boolean isPropertiesTag(final Qualifier qualifier, final Feature feature)
    
    tjc's avatar
    tjc committed
      {
        if(qualifier.getName().equals("ID") ||
    
           qualifier.getName().equals("Name") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("feature_id") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("Parent") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("Derives_from") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("feature_relationship_rank") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("timelastmodified") ||
    
           qualifier.getName().equals("isObsolete") ||
    
           qualifier.getName().equals("Start_range") ||
           qualifier.getName().equals("End_range") ||
    
    tjc's avatar
    tjc committed
           qualifier.getName().equals("codon_start") ||
    
    tjc's avatar
    tjc committed
           ChadoTransactionManager.isSynonymTag(qualifier.getName(), 
               (GFFStreamFeature)feature.getEmblFeature()))
    
    tjc's avatar
    tjc committed
          return true;
        return false;
      }
      
    
    tjc's avatar
    tjc committed
      private Component createGffQualifiersComponent()
    
    tjc's avatar
    tjc committed
      {
    
        empty = true;
    
    tjc's avatar
    tjc committed
        GridBagConstraints c = new GridBagConstraints();
    
    tjc's avatar
    tjc committed
        JPanel gridPanel = new JPanel(new GridBagLayout());
        gridPanel.setBackground(Color.white);
    
    
        int nrow = 0;
    
    tjc's avatar
    tjc committed
        
        if(showNames)
        {
          addNames(c, gridPanel, nrow++);
          nrow = addSynonyms(c, gridPanel, nrow);
        }
    
    tjc's avatar
    tjc committed
        if(showParent)
          addParent(c, gridPanel, nrow++);
    
        
        // phase of translation wrt / codon_start
        if(feature.getEntry().getEntryInformation().isValidQualifier(
           feature.getKey(), "codon_start"))
          addPhaseComponent(c, gridPanel, nrow++);
    
    
    tjc's avatar
    tjc committed
        // partial/obsolete options
        if(showOptions)
          addOptions(c, gridPanel, nrow);
    
    tjc's avatar
    tjc committed
        // add buttons and timelastmodified
        if(showTimeLastModified)
          addTimeLastModified(c, gridPanel, nrow);
    
        return gridPanel;
      }
      
      /**
       * Add uniquename and name to the panel.
       * @param cellDimension
       * @param c
       * @param gridPanel
       * @param nrows
       */
    
      private void addNames(GridBagConstraints c, 
    
                            JPanel gridPanel, 
                            int nrows)
      {
        Qualifier idQualifier   = gffQualifiers.getQualifierByName("ID");
        Qualifier nameQualifier = gffQualifiers.getQualifierByName("Name");
       
        final String uniquename = (String)idQualifier.getValues().get(0);
        uniquenameTextField = new JTextField(uniquename);
    
        uniquenameTextField.setPreferredSize(calcPreferredMaxTextFieldWidth());
    
        uniquenameTextField.setCaretPosition(0);
    
        
        JLabel idField = new JLabel("ID ");
        idField.setFont(getFont().deriveFont(Font.BOLD));
        idField.setHorizontalAlignment(SwingConstants.RIGHT);
        idField.setPreferredSize(calcPreferredLabelWidth());
    
    
        c.gridx = 0;
        c.gridy = nrows;
        c.ipadx = 5;
        c.anchor = GridBagConstraints.EAST;
    
        gridPanel.add(idField, c);
    
        c.gridx = 1;
        c.ipadx = 0;
        c.anchor = GridBagConstraints.WEST;
        gridPanel.add(uniquenameTextField, c);
    
        Qualifier featIdQualifier = gffQualifiers.getQualifierByName("feature_id");
        if (featIdQualifier != null)
        {
    
    tjc's avatar
    tjc committed
          Qualifier timeQualifier = gffQualifiers.getQualifierByName("timelastmodified");
          String time = null;
          if (timeQualifier != null)
            time = (String) timeQualifier.getValues().get(0);
          
    
          String parent = getParentString();
          String tt = "feature_id=" +
    
    tjc's avatar
    tjc committed
            (String) featIdQualifier.getValues().get(0) +
            (parent == null ? "" : "\n"+parent)+
            (time == null ? "" : "\n"+time);
    
    
          idField.setToolTipText(tt);
          uniquenameTextField.setToolTipText(tt);
    
        }
        
        if(feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
          uniquenameTextField.setEditable(false);
    
        if (!feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
    
          primaryNameTextField = new JTextField();
    
          primaryNameTextField.setPreferredSize(calcPreferredMaxTextFieldWidth());
    
          
          if (nameQualifier != null)
    
            primaryNameTextField.setText((String) nameQualifier.getValues().get(0));
    
            empty = false;
          }
    
    tjc's avatar
    tjc committed
    
    
          c.gridx = 2;
    
          c.ipadx = 5;
          c.anchor = GridBagConstraints.EAST;
    
          JLabel lab = new JLabel("  Name");
          lab.setFont(getFont().deriveFont(Font.BOLD));
          gridPanel.add(lab, c);
    
          c.gridx = 3;
    
          c.ipadx = 0;
    
          c.anchor = GridBagConstraints.WEST;
    
          gridPanel.add(primaryNameTextField, c);
        }
    
    tjc's avatar
    tjc committed
        
    
        ActionListener addAction = new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
            addSynonym();
          }  
        };
        
        AddButton addSynonymButton = new AddButton(addAction, "Add Synonym");
    
    tjc's avatar
    tjc committed
        c.gridx = 4;
        gridPanel.add(addSynonymButton, c);
    
      }
    
      /**
       * Get the parent feature name.
       * @return
       */
      private String getParentString()
      {
        Qualifier parentQualifier      = gffQualifiers.getQualifierByName("Parent");
        if(parentQualifier != null && 
           parentQualifier.getValues().size() == 1)
        {
          StringVector parents = parentQualifier.getValues();
          return "Parent: "+parents.get(0);
        }
    
        Qualifier derivesFromQualifier = gffQualifiers.getQualifierByName("Derives_from");
        if(derivesFromQualifier != null && 
           derivesFromQualifier.getValues().size() == 1)
        {
          StringVector derivesFroms = derivesFromQualifier.getValues();
          return "Derives from: "+derivesFroms.get(0);
        }
        return null;
      }
      
      /**
       * Add Parent or Derives_from.
       * @param c
       * @param gridPanel
       * @param nrows
       */
      private void addParent(GridBagConstraints c,
                             JPanel gridPanel,
                             int nrows)
      {
        Qualifier parentQualifier = gffQualifiers.getQualifierByName("Parent");
        if(parentQualifier != null && 
           parentQualifier.getValues().size() == 1)
        {
          StringVector parents = parentQualifier.getValues();
          JLabel parentField = new JLabel("Parent");
          parentField.setFont(getFont().deriveFont(Font.BOLD));
          c.gridx = 0;
          c.gridy = nrows;
          c.ipadx = 5;
          c.fill = GridBagConstraints.NONE;
          c.anchor = GridBagConstraints.EAST;
          gridPanel.add(parentField, c);
          
          JTextField parent = new JTextField(" "+(String) parents.get(0));
          parent.setPreferredSize(calcPreferredMaxTextFieldWidth());
          parent.setBorder(BorderFactory.createEmptyBorder());
          c.gridx = 1;
          c.anchor = GridBagConstraints.WEST;
          gridPanel.add(parent, c);
          return;
        }
    
        Qualifier derivesFromQualifier = gffQualifiers.getQualifierByName("Derives_from");
        if(derivesFromQualifier != null && 
           derivesFromQualifier.getValues().size() == 1)
        {
          StringVector derivesFroms = derivesFromQualifier.getValues();
          JLabel derivesFromsField = new JLabel("Derives from");
          derivesFromsField.setFont(getFont().deriveFont(Font.BOLD));
          c.gridx = 0;
          c.gridy = nrows;
          c.ipadx = 5;
          c.fill = GridBagConstraints.NONE;
          c.anchor = GridBagConstraints.EAST;
          gridPanel.add(derivesFromsField, c);
          
          JTextField parent = new JTextField(" "+(String) derivesFroms.get(0));
          parent.setPreferredSize(calcPreferredMaxTextFieldWidth());
          parent.setBorder(BorderFactory.createEmptyBorder());
          c.gridx = 1;
          c.anchor = GridBagConstraints.WEST;
          gridPanel.add(parent, c);
        }
    
      }
      
      /**
       * Add synonyms to the panel.
       * @param c
       * @param gridPanel
       * @param nrows
       * @return
       */
      private int addSynonyms(GridBagConstraints c, JPanel gridPanel, int nrows)
      {
        int maxSynonymWidth = 0;
        int maxLabelWidth = new JLabel("previous_systematic_id ").getPreferredSize().width;
        
        for(int i=0; i<gffQualifiers.size(); i++)
    
    tjc's avatar
    tjc committed
        {
    
          final Qualifier qualifier = (Qualifier)gffQualifiers.get(i);
          if( ChadoTransactionManager.isSynonymTag(qualifier.getName(), 
              (GFFStreamFeature)feature.getEmblFeature()) &&
              isSystematicId(qualifier.getName()))
    
    tjc's avatar
    tjc committed
          {
    
            addSynonymComponent(qualifier, c, gridPanel, nrows++,
                maxLabelWidth, maxSynonymWidth);  
    
    tjc's avatar
    tjc committed
          }
        }
    
        
        for(int i=0; i<gffQualifiers.size(); i++)
    
          final Qualifier qualifier = (Qualifier)gffQualifiers.get(i);
          if( ChadoTransactionManager.isSynonymTag(qualifier.getName(), 
              (GFFStreamFeature)feature.getEmblFeature()) &&
              !isSystematicId(qualifier.getName()))
    
            addSynonymComponent(qualifier, c, gridPanel, nrows++, 
                maxLabelWidth, maxSynonymWidth);  
    
        return nrows;
      }
      
      
      /**
       * Add partial and obsolete options to the panel.
       * @param c
       * @param gridPanel
       * @param nrows
       */
      private void addOptions(GridBagConstraints c, JPanel gridPanel, int nrows)
      {
        Qualifier isPartialQualfier5;
        Qualifier isPartialQualfier3;
        if(feature.isForwardFeature())
    
          isPartialQualfier5   = gffQualifiers.getQualifierByName("Start_range");
          isPartialQualfier3   = gffQualifiers.getQualifierByName("End_range");
    
          isPartialQualfier3   = gffQualifiers.getQualifierByName("Start_range");
          isPartialQualfier5   = gffQualifiers.getQualifierByName("End_range");
    
    tjc's avatar
    tjc committed
        }
    
        Box optionsBox = Box.createHorizontalBox();
        partialField5prime = new JCheckBox("partial 5'", 
    
    tjc's avatar
    tjc committed
            ( isPartialQualfier5 != null ) ? true : false);
    
        Dimension d = calcPreferred(partialField5prime.getPreferredSize().width);
        partialField5prime.setPreferredSize(d);
    
        partialField5prime.setOpaque(false);
    
        partialField5prime.addActionListener(new ActionListener(){
          public void actionPerformed(ActionEvent e)
          {
            checkPartial();
          }
        });
        
    
        optionsBox.add(partialField5prime);
    
        partialField3prime = new JCheckBox("partial 3'", 
    
    tjc's avatar
    tjc committed
            ( isPartialQualfier3 != null ) ? true : false);
    
        partialField3prime.setPreferredSize(d);
    
        partialField3prime.setOpaque(false);
    
        partialField3prime.addActionListener(new ActionListener(){
          public void actionPerformed(ActionEvent e)
          {
            checkPartial();
          }
        });
    
        optionsBox.add(partialField3prime);
    
        Qualifier obsoleteQualifier = gffQualifiers.getQualifierByName("isObsolete");
    
    tjc's avatar
    tjc committed
        if(obsoleteQualifier == null)
    
          isObsolete = false;
        else
          isObsolete = Boolean.parseBoolean((String) obsoleteQualifier.getValues().get(0));
    
        obsoleteField = new JCheckBox("obsolete", isObsolete);
        obsoleteField.setPreferredSize(calcPreferred(obsoleteField.getPreferredSize().width));
    
        obsoleteField.setOpaque(false);
        obsoleteField.addActionListener(new ActionListener()
    
    tjc's avatar
    tjc committed
        {
          public void actionPerformed(ActionEvent e)
    
          {
            int result = JOptionPane.showConfirmDialog(
                PropertiesPanel.this, "Change this feature to be "+
                (obsoleteField.isSelected() ? "obsolete!" : "not obsolete!"), 
                "Change obsolete option", JOptionPane.OK_CANCEL_OPTION);
            if(result == JOptionPane.CANCEL_OPTION)
              obsoleteField.setSelected(!obsoleteField.isSelected());
    
    tjc's avatar
    tjc committed
          }
        });
    
        optionsBox.add(obsoleteField);
    
        c.gridx = 0;
        c.anchor = GridBagConstraints.WEST;
        c.gridwidth = GridBagConstraints.REMAINDER;
        c.gridy = nrows;
        gridPanel.add(optionsBox, c);
        c.gridwidth = 1;
    
    tjc's avatar
    tjc committed
      }
      
    
    tjc's avatar
    tjc committed
      private void addTimeLastModified(GridBagConstraints c, JPanel gridPanel, int nrows)
      {
        Qualifier timeQualifier = gffQualifiers.getQualifierByName("timelastmodified");
        if (timeQualifier != null)
        {
          String time = (String) timeQualifier.getValues().get(0);
          JLabel timeLabel = new JLabel(time);
          timeLabel.setEnabled(false);
          timeLabel.setToolTipText("time last modified");
          
          c.gridy = ++nrows;
          c.gridx = 4;
          c.gridwidth = GridBagConstraints.REMAINDER;
          c.anchor = GridBagConstraints.EAST;
          gridPanel.add(timeLabel,c);
        }   
      }
      
    
    tjc's avatar
    tjc committed
      public void updateFromFeature(final Feature feature)
      {
    
    tjc's avatar
    tjc committed
        this.feature = feature;
    
    tjc's avatar
    tjc committed
        removeAll();
        if(gffQualifiers != null)
          feature.removeFeatureChangeListener(this);
        gffQualifiers = feature.getQualifiers().copy();
        
        gffQualifiers = new QualifierVector();
        final QualifierVector qualifiers = feature.getQualifiers();  
        for(int i = 0 ; i < qualifiers.size(); ++i) 
        {
          Qualifier qualifier = (Qualifier)qualifiers.elementAt(i);
    
    tjc's avatar
    tjc committed
          if(isPropertiesTag(qualifier, feature))
    
    tjc's avatar
    tjc committed
            gffQualifiers.addElement(qualifier.copy());
        }
       
        feature.addFeatureChangeListener(this);  
    
    tjc's avatar
    tjc committed
        add(createGffQualifiersComponent());
    
    tjc's avatar
    tjc committed
        revalidate();
    
        repaint();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       * Get the latest (edited) controlled vocab qualifiers
       * @return
       */
    
    tjc's avatar
    tjc committed
      public QualifierVector getGffQualifiers(final Feature feature)
    
    tjc's avatar
    tjc committed
      {
        // check editable components for changes
        
        Qualifier idQualifier = gffQualifiers.getQualifierByName("ID");
    
    tjc's avatar
    tjc committed
        if(showNames &&
            !((String)(idQualifier.getValues().get(0))).equals(uniquenameTextField.getText()))
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          if(!uniquenameTextField.getText().equals(""))
    
    tjc's avatar
    tjc committed
          {
    
    tjc's avatar
    tjc committed
            final String newName = uniquenameTextField.getText().trim();
            final String oldName = ((String) (idQualifier.getValues().get(0))).trim();
    
    tjc's avatar
    tjc committed
            gffQualifiers.remove(idQualifier);
    
    tjc's avatar
    tjc committed
            idQualifier = new Qualifier("ID", newName);
    
    tjc's avatar
    tjc committed
            gffQualifiers.addElement(idQualifier);
    
    tjc's avatar
    tjc committed
            
            GFFStreamFeature gffFeature = (GFFStreamFeature)feature.getEmblFeature();
            if(gffFeature.getChadoGene() != null)
            {
    
              Set<uk.ac.sanger.artemis.io.Feature> children = 
            	  gffFeature.getChadoGene().getChildren(gffFeature);
    
    tjc's avatar
    tjc committed
              gffFeature.getChadoGene().updateUniqueName(oldName, newName, children);
            }
    
    tjc's avatar
    tjc committed
          }
        }
    
    tjc's avatar
    tjc committed
        if(!feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
    
    tjc's avatar
    tjc committed
          Qualifier nameQualifier = gffQualifiers.getQualifierByName("Name");
          if( (nameQualifier != null &&
           !((String)(nameQualifier.getValues().get(0))).equals(primaryNameTextField.getText())) ||
           (primaryNameTextField != null && !primaryNameTextField.getText().equals("")))
    
    tjc's avatar
    tjc committed
            gffQualifiers.remove(nameQualifier);   
            final String newName = primaryNameTextField.getText().trim();
            nameQualifier = new Qualifier("Name", newName);
    
            gffQualifiers.addElement(nameQualifier);
          }
        }
        
    
    tjc's avatar
    tjc committed
        if(phaseButtonGroup != null)
        {
          String selectionCmd = phaseButtonGroup.getSelection().getActionCommand();
          
          Qualifier phaseQualifier = gffQualifiers.getQualifierByName("codon_start");
          if(phaseQualifier == null)
          {
            if(!selectionCmd.equals(""))
            {
              phaseQualifier = new Qualifier("codon_start", selectionCmd);
              gffQualifiers.addElement(phaseQualifier);
            }
          }
          else
          {
            String oldPhase = (String)phaseQualifier.getValues().get(0);
            if(!oldPhase.equals(phaseButtonGroup))
            {
              gffQualifiers.remove(phaseQualifier);
              if(!selectionCmd.equals(""))
              {
                phaseQualifier = new Qualifier("codon_start", selectionCmd);
                gffQualifiers.addElement(phaseQualifier);
              }
            }
          }
        }
        
    
        Qualifier isObsoleteQualifier = gffQualifiers.getQualifierByName("isObsolete");
        if(isObsoleteQualifier != null)
        {
    
    tjc's avatar
    tjc committed
          if(showOptions)
          {
            String isObsoleteOld = (String) isObsoleteQualifier.getValues().get(0);
            String isObsoleteNew = Boolean.toString(obsoleteField.isSelected());
    
            if (!isObsoleteNew.equals(isObsoleteOld))
            {
              gffQualifiers.remove(isObsoleteQualifier);
              isObsoleteQualifier = new Qualifier("isObsolete", isObsoleteNew);
              gffQualifiers.addElement(isObsoleteQualifier);
              obsoleteChanged = true;
            }
          } 
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        Qualifier isPartial5primeQualifier; 
        if(feature.isForwardFeature())
    
          isPartial5primeQualifier = gffQualifiers.getQualifierByName("Start_range");
    
    tjc's avatar
    tjc committed
        else
    
          isPartial5primeQualifier = gffQualifiers.getQualifierByName("End_range");
    
    tjc's avatar
    tjc committed
        if(isPartial5primeQualifier != null)
        {
    
    tjc's avatar
    tjc committed
          if(showOptions && !partialField5prime.isSelected())
    
    tjc's avatar
    tjc committed
            gffQualifiers.remove(isPartial5primeQualifier);
    
            partialChanged = true;
          }
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        else if(showOptions && partialField5prime.isSelected())
    
    tjc's avatar
    tjc committed
        {
          if(feature.isForwardFeature())
    
            gffQualifiers.addElement(new Qualifier("Start_range",".,."));
    
    tjc's avatar
    tjc committed
          else
    
            gffQualifiers.addElement(new Qualifier("End_range",".,."));
    
          partialChanged = true;
    
    tjc's avatar
    tjc committed
        }
        
        Qualifier isPartial3primeQualifier;
        if(feature.isForwardFeature())
    
          isPartial3primeQualifier = gffQualifiers.getQualifierByName("End_range");
    
    tjc's avatar
    tjc committed
        else
    
          isPartial3primeQualifier = gffQualifiers.getQualifierByName("Start_range");
    
    tjc's avatar
    tjc committed
        if(isPartial3primeQualifier != null)
        {
    
    tjc's avatar
    tjc committed
          if(showOptions && !partialField3prime.isSelected())
    
    tjc's avatar
    tjc committed
            gffQualifiers.remove(isPartial3primeQualifier);
    
            partialChanged = true;
          }
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        else if(showOptions && partialField3prime.isSelected())
    
    tjc's avatar
    tjc committed
        {
          if(feature.isForwardFeature())
    
            gffQualifiers.addElement(new Qualifier("End_range",".,."));
    
    tjc's avatar
    tjc committed
          else
    
            gffQualifiers.addElement(new Qualifier("Start_range",".,."));
    
          partialChanged = true;
    
    tjc's avatar
    tjc committed
        }
    
    
    tjc's avatar
    tjc committed
        return gffQualifiers;
      }
      
    
       * If the partial/isObsolete qualifier for this feature has been changed this 
       * method updates the partial/isObsolete qualifier of the children feature.
    
      public void updateSettings()
    
        if(partialChanged)
          updatePartialSettings((GFFStreamFeature)feature.getEmblFeature());
    
        if(!obsoleteChanged)
          return;
        
        obsoleteChanged = false;
    
        updateObsoleteSettings((GFFStreamFeature)feature.getEmblFeature());
      }
      
      public static void updateObsoleteSettings(GFFStreamFeature gffFeature)
      {
    
        Qualifier isObsoleteQualifier = gffFeature.getQualifierByName("isObsolete");
        String isObsoleteNew = (String) isObsoleteQualifier.getValues().get(0);
        if(isObsoleteNew.equals("true"))
          gffFeature.setVisible(false);
        else
          gffFeature.setVisible(true); 
        
    
    tjc's avatar
    tjc committed
        if(gffFeature.getChadoGene() == null)
          return;
    
        Set<uk.ac.sanger.artemis.io.Feature> children =
        	gffFeature.getChadoGene().getChildren(gffFeature);
    
     
        if(children.size() > 0)
        {
          Qualifier idQualifier = gffFeature.getQualifierByName("ID");
          
    
          int select = JOptionPane.showConfirmDialog(null, 
    
              "Make children of "+idQualifier.getValues().get(0)+"\n"+
              (isObsoleteNew.equals("true") ? "obsolete?" : "not obsolete?"), 
              "Update Children", 
              JOptionPane.YES_NO_OPTION);
          
          if(select == JOptionPane.YES_OPTION)
          {
            try
            {
    
              Iterator<uk.ac.sanger.artemis.io.Feature> it = children.iterator();
    
              while(it.hasNext())
              {
                GFFStreamFeature gffChildFeature = (GFFStreamFeature)it.next();
                Feature f = (Feature)gffChildFeature.getUserData();
                f.setQualifier(new Qualifier("isObsolete", isObsoleteNew));
                gffChildFeature.setVisible(true);    
                
                if(isObsoleteNew.equals("true") ||
                   GeneUtils.isHiddenFeature( gffChildFeature.getKey().getKeyString() ))
                  gffChildFeature.setVisible(false);
              }
            }
            catch(Exception e)
            {
              e.printStackTrace();
            }
          }    
        }  
      }
    
    
      /**
       * Change partial settings of child featuers.
       * @param gffFeature
       */
    
      private void updatePartialSettings(GFFStreamFeature gffFeature)
    
      {
        if(!partialChanged)
          return;
        partialChanged = false;
        
        if(gffFeature.getChadoGene() == null)
          return;
    
        Qualifier fminQualifier = gffFeature.getQualifierByName("Start_range");
        Qualifier fmaxQualifier = gffFeature.getQualifierByName("End_range");
    
        ChadoCanonicalGene chadoGene = gffFeature.getChadoGene();
        Set<uk.ac.sanger.artemis.io.Feature> children = chadoGene.getChildren(gffFeature);
    
    
        if(children.size() > 0)
        {
          int select = JOptionPane.showConfirmDialog(null, 
              "Update partial setting on child features?", 
              "Update Children", JOptionPane.YES_NO_OPTION);
          if(select != JOptionPane.YES_OPTION)
            return;
          try
          {
            Iterator<uk.ac.sanger.artemis.io.Feature> it = children.iterator();
            while(it.hasNext())
            {
    
    tcarver's avatar
    tcarver committed
              final GFFStreamFeature gffChildFeature = (GFFStreamFeature)it.next();
              final Feature f = (Feature)gffChildFeature.getUserData();
    
              final String keyStr = f.getKey().getKeyString();
    
              if(keyStr.equals("five_prime_UTR") || keyStr.equals("three_prime_UTR"))
              {
    
    tcarver's avatar
    tcarver committed
                String fName = chadoGene.getQualifier(gffChildFeature, "ID");
    
                boolean isFwd = !f.getLocation().isComplement();
                if(fName != null && !chadoGene.isFirstUtr(fName, isFwd))
                  continue;
                
                if( (keyStr.equals("five_prime_UTR")  &&  isFwd) ||
                    (keyStr.equals("three_prime_UTR") && !isFwd) )
                {
                  if(fminQualifier != null)
    
                    f.setQualifier(new Qualifier("Start_range",".,."));
    
                    f.removeQualifierByName("Start_range");
    
                }
                else
                {
                  if(fmaxQualifier != null)
    
                    f.setQualifier(new Qualifier("End_range",".,."));
    
                    f.removeQualifierByName("End_range");
    
              {
                if(fminQualifier != null)
    
                  f.setQualifier(new Qualifier("Start_range",".,."));
    
                  f.removeQualifierByName("Start_range");
    
                if(fmaxQualifier != null)
    
                  f.setQualifier(new Qualifier("End_range",".,."));
    
                  f.removeQualifierByName("End_range");
    
            }
          }
          catch(Exception e)
          {
            e.printStackTrace();
          }  
        }  
      }
    
      /**
       * Partial settings are made on the gene or transcript features.
       * Provide a warning if this is not the case.
       */
      private void checkPartial()
      {
        String keyStr = feature.getKey().getKeyString();
        if(keyStr.equals("polypeptide") || 
           keyStr.equals("CDS") || 
           keyStr.equals("pseudogenic_exon"))
        {
          JOptionPane.showMessageDialog(null, 
              "Partial settings should be updated on the transcript\n"+
              "or gene feature not a "+keyStr+". Please make this change\n"+
              "on the transcript or gene feature now.", 
              "Error", JOptionPane.WARNING_MESSAGE);
        }
      }
      
    
    tjc's avatar
    tjc committed
      private boolean isSystematicId(final String synonymType)
      {
        if(synonymType.indexOf("systematic_id") > -1)
          return true;
        return false;
      }
    
      private void removeSynonym(String synonymName, String qualifierValue)
      {   
        int select = JOptionPane.showConfirmDialog(null, 
            "Delete "+qualifierValue+"?",
            "Select synonym type", JOptionPane.OK_CANCEL_OPTION);
    
        if(select != JOptionPane.OK_OPTION)
    
    tjc's avatar
    tjc committed
          return;
        
    
        StringVector values =
          gffQualifiers.getQualifierByName(synonymName).getValues();
    
    tjc's avatar
    tjc committed
        
        if(values.size()==1)
          gffQualifiers.removeQualifierByName(synonymName);
        else
        {
          int index = gffQualifiers.indexOfQualifierWithName(synonymName);
    
          values.remove(qualifierValue);
          gffQualifiers.remove(index);
    
    tjc's avatar
    tjc committed
          gffQualifiers.add(index, new Qualifier(synonymName, values));
        }
        
        removeAll();
        add(createGffQualifiersComponent());
        revalidate();
    
        repaint();
    
    tjc's avatar
    tjc committed
      private void addSynonym()
      {
    
        final Vector<CvTerm> synonyms = DatabaseDocument.getCvterms("", 
    
    tjc's avatar
    tjc committed
            ChadoTransactionManager.SYNONYM_TAG_CVNAME, false);
    
    tjc's avatar
    tjc committed
        final JExtendedComboBox list = new JExtendedComboBox(synonyms);
        final String options[] = { "CANCEL", "NEXT>"};   
        
        int select = JOptionPane.showOptionDialog(null, list,
            "Select synonym type",
             JOptionPane.YES_NO_CANCEL_OPTION,
             JOptionPane.QUESTION_MESSAGE,
             null,
             options,
             options[1]);
        
        if(select == 0)
          return;
        
        Box xBox = Box.createHorizontalBox();
        final String synonymName = ((CvTerm)list.getSelectedItem()).getName();
        final JLabel name = new JLabel( synonymName );
        xBox.add(name);
        
        final JTextField newSynonym = new JTextField(15);
        xBox.add(newSynonym);
        
        final JCheckBox current = new JCheckBox("make current", true);
    
        xBox.add(current);
    
    tjc's avatar
    tjc committed
        
        select = JOptionPane.showConfirmDialog(null, xBox, 
            "Input name", JOptionPane.OK_CANCEL_OPTION);
        
        if(select == JOptionPane.CANCEL_OPTION || newSynonym.getText().equals(""))
          return;
        
        Qualifier synonymQualifier = gffQualifiers.getQualifierByName(synonymName);
        
        String newSynonymValue = newSynonym.getText();
    
        if(!current.isSelected())
    
    tjc's avatar
    tjc committed
          newSynonymValue = newSynonymValue + ";current=false";
        
        if(synonymQualifier == null)
        {
          synonymQualifier = new Qualifier(synonymName, newSynonymValue);
          gffQualifiers.add(synonymQualifier);
        }
        else
          synonymQualifier.addValue(newSynonymValue);
        
    
    tjc's avatar
    tjc committed
        final StringVector newValues = synonymQualifier.getValues();
        
        /*
    
    tjc's avatar
    tjc committed
        final StringVector newValues = new StringVector();
        for(int i=0; i<values.size(); i++)
        {
          String thisValue = (String) values.get(i);
          StringVector str = StringVector.getStrings(thisValue, ";");
          String synonymValue = (String) str.get(0);
          
    
    tjc's avatar
    tjc committed
          if(isSystematicId(synonymName) && !synonymValue.equals(newSynonymValue))
    
    tjc's avatar
    tjc committed
            if(current.isSelected() && !thisValue.endsWith(";current=false"))
              thisValue = thisValue + ";current=false";
          
          newValues.add(thisValue);
        }
    
    tjc's avatar
    tjc committed
        */
    
    tjc's avatar
    tjc committed
    
        int index = gffQualifiers.indexOfQualifierWithName(synonymName);
        if(index == -1)
          gffQualifiers.setQualifier(new Qualifier(synonymName,newValues));
        else
        {
          gffQualifiers.remove(index);
          gffQualifiers.add(index, new Qualifier(synonymName,newValues));
        }
        removeAll();
        add(createGffQualifiersComponent());
        revalidate();
      }
      
    
    tjc's avatar
    tjc committed
      /**
       * Add codon_start component to the properties panel
       * @param c
       * @param gridPanel
       */
    
      private void addPhaseComponent(final GridBagConstraints c, final JPanel gridPanel, int nrows)
    
    tjc's avatar
    tjc committed
      {
        Qualifier qualifierCodonStart = gffQualifiers.getQualifierByName("codon_start");
        phaseButtonGroup = new ButtonGroup();
     
        JRadioButton phase1 = new JRadioButton("1");
        phase1.setOpaque(false);
        phase1.setActionCommand("1");
        phaseButtonGroup.add(phase1);
        JRadioButton phase2 = new JRadioButton("2");
        phase2.setOpaque(false);
        phase2.setActionCommand("2");
        phaseButtonGroup.add(phase2);
        JRadioButton phase3 = new JRadioButton("3");
        phase3.setOpaque(false);
        phase3.setActionCommand("3");
        phaseButtonGroup.add(phase3);
        JRadioButton phaseNone = new JRadioButton("Default");
        phaseNone.setOpaque(false);
        phaseNone.setActionCommand("");
        phaseButtonGroup.add(phaseNone);
        
        if(qualifierCodonStart == null)
          phaseNone.setSelected(true);
        else
        {
          int codon_start = feature.getCodonStart();
          empty = false;
          switch (codon_start)
          {
            case 1:  phase1.setSelected(true); break;
            case 2:  phase2.setSelected(true); break;
            case 3:  phase3.setSelected(true); break;
            default: phaseNone.setSelected(true);break;
          }
        }
        
        Box xBox = Box.createHorizontalBox();
    
        c.gridx = 0;
        c.gridy = nrows;
    
    tjc's avatar
    tjc committed
        c.anchor = GridBagConstraints.EAST;
        c.fill = GridBagConstraints.NONE;
        c.ipadx = 5;
    
        
        JLabel lab = new JLabel("Codon Start");
        lab.setFont(getFont().deriveFont(Font.BOLD));
        gridPanel.add(lab, c);
    
    tjc's avatar
    tjc committed
        xBox.add(phase1);
        xBox.add(phase2);
        xBox.add(phase3);
        xBox.add(phaseNone);
        xBox.add(Box.createHorizontalGlue());
    
        c.gridx = 1;
    
    tjc's avatar
    tjc committed
        c.anchor = GridBagConstraints.WEST;
        c.ipadx = 0;
    
        c.gridwidth = 2;
    
    tjc's avatar
    tjc committed
        gridPanel.add(xBox, c);
    
        c.gridwidth = 1;
    
    tjc's avatar
    tjc committed
      /**
       * Add the synonym components
       * @param qualifier
       * @param c
       * @param gridPanel
       * @param nrows
       * @param maxLabelWidth
       * @param maxSynonymWidth
       * @return
       */
      private void addSynonymComponent(final Qualifier qualifier, 
                                       final GridBagConstraints c, 
                                       final JPanel gridPanel, 
                                       final int nrows, 
                                       final int maxLabelWidth,
                                       int maxSynonymWidth)