Skip to content
Snippets Groups Projects
PropertiesPanel.java 31 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
        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);
      }
      
      /**
       * 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);
    
    
    tjc's avatar
    tjc committed
        if(showNames)
        {
    
    tcarver's avatar
    tcarver committed
          addNames(c, gridPanel);
          addSynonyms(c, gridPanel);
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        if(showParent)
    
    tcarver's avatar
    tcarver committed
        {
          addParent(c, gridPanel, "Parent");
          addParent(c, gridPanel, "Derives_from");
        }
    
        
        // phase of translation wrt / codon_start
        if(feature.getEntry().getEntryInformation().isValidQualifier(
           feature.getKey(), "codon_start"))
    
    tcarver's avatar
    tcarver committed
          addPhaseComponent(c, gridPanel);
    
    tjc's avatar
    tjc committed
        // partial/obsolete options
        if(showOptions)
    
    tcarver's avatar
    tcarver committed
          addOptions(c, gridPanel);
    
    tjc's avatar
    tjc committed
        // add buttons and timelastmodified
        if(showTimeLastModified)
    
    tcarver's avatar
    tcarver committed
          addTimeLastModified(c, gridPanel);
    
        return gridPanel;
      }
      
      /**
       * Add uniquename and name to the panel.
       * @param c
       * @param gridPanel
       */
    
    tcarver's avatar
    tcarver committed
      private void addNames(GridBagConstraints c, JPanel gridPanel)
    
      {
        Qualifier idQualifier   = gffQualifiers.getQualifierByName("ID");
        Qualifier nameQualifier = gffQualifiers.getQualifierByName("Name");
       
    
    tcarver's avatar
    tcarver committed
        final String uniquename = 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;
    
    tcarver's avatar
    tcarver committed
        c.gridy++;
    
        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)
    
    tcarver's avatar
    tcarver committed
            time = timeQualifier.getValues().get(0);
    
    tjc's avatar
    tjc committed
          
    
          String parent = getParentString();
          String tt = "feature_id=" +
    
    tcarver's avatar
    tcarver committed
            featIdQualifier.getValues().get(0) +
    
    tjc's avatar
    tjc committed
            (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()
      {
    
    tcarver's avatar
    tcarver committed
        Qualifier parentQual = gffQualifiers.getQualifierByName("Parent");
        if(parentQual != null && 
           parentQual.getValues().size() == 1)
          return "Parent: "+parentQual.getValues().get(0);
    
        Qualifier derivesFromQual = gffQualifiers.getQualifierByName("Derives_from");
        if(derivesFromQual != null && 
           derivesFromQual.getValues().size() == 1)
          return "Derives from: "+derivesFromQual.getValues().get(0);
    
    
        return null;
      }
      
      /**
       * Add Parent or Derives_from.
       * @param c
       * @param gridPanel
       */
      private void addParent(GridBagConstraints c,
                             JPanel gridPanel,
    
    tcarver's avatar
    tcarver committed
                             String parentName)
    
    tcarver's avatar
    tcarver committed
        Qualifier parentQualifier = gffQualifiers.getQualifierByName(parentName);
    
        if(parentQualifier != null && 
           parentQualifier.getValues().size() == 1)
        {
    
    tcarver's avatar
    tcarver committed
          JLabel parentField = new JLabel(parentName);
    
          parentField.setFont(getFont().deriveFont(Font.BOLD));
          c.gridx = 0;
    
    tcarver's avatar
    tcarver committed
          c.gridy++;
    
          c.ipadx = 5;
          c.fill = GridBagConstraints.NONE;
          c.anchor = GridBagConstraints.EAST;
          gridPanel.add(parentField, c);
          
    
    tcarver's avatar
    tcarver committed
          JTextField parent = new JTextField(" "+ parentQualifier.getValues().get(0));
    
          parent.setPreferredSize(calcPreferredMaxTextFieldWidth());
          parent.setBorder(BorderFactory.createEmptyBorder());
          c.gridx = 1;
          c.anchor = GridBagConstraints.WEST;
          gridPanel.add(parent, c);
          return;
        }
    
      }
      
      /**
       * Add synonyms to the panel.
       * @param c
       * @param gridPanel
       * @param nrows
       */
    
    tcarver's avatar
    tcarver committed
      private void addSynonyms(GridBagConstraints c, JPanel gridPanel)
    
    tcarver's avatar
    tcarver committed
        for(Qualifier qualifier: gffQualifiers)
    
    tjc's avatar
    tjc committed
        {
    
          if( ChadoTransactionManager.isSynonymTag(qualifier.getName(), 
              (GFFStreamFeature)feature.getEmblFeature()) &&
              isSystematicId(qualifier.getName()))
    
    tjc's avatar
    tjc committed
          {
    
    tcarver's avatar
    tcarver committed
            addSynonymComponent(qualifier, c, gridPanel);  
    
    tjc's avatar
    tjc committed
          }
        }
    
    tcarver's avatar
    tcarver committed
        for(Qualifier qualifier: gffQualifiers)
    
          if( ChadoTransactionManager.isSynonymTag(qualifier.getName(), 
              (GFFStreamFeature)feature.getEmblFeature()) &&
              !isSystematicId(qualifier.getName()))
    
    tcarver's avatar
    tcarver committed
            addSynonymComponent(qualifier, c, gridPanel);  
    
      }
      
      
      /**
       * Add partial and obsolete options to the panel.
       * @param c
       * @param gridPanel
       */
    
    tcarver's avatar
    tcarver committed
      private void addOptions(GridBagConstraints c, JPanel gridPanel)
    
    tcarver's avatar
    tcarver committed
        final Qualifier isPartialQualfier5;
        final Qualifier isPartialQualfier3;
    
        if(feature.isForwardFeature())
    
    tcarver's avatar
    tcarver committed
          isPartialQualfier5 = gffQualifiers.getQualifierByName("Start_range");
          isPartialQualfier3 = gffQualifiers.getQualifierByName("End_range");
    
    tcarver's avatar
    tcarver committed
          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);
    
    tcarver's avatar
    tcarver committed
        Qualifier obsoleteQual = gffQualifiers.getQualifierByName("isObsolete");
        obsoleteField = new JCheckBox("obsolete", (obsoleteQual == null ? false : 
          Boolean.parseBoolean(obsoleteQual.getValues().get(0))));
    
        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;
    
    tcarver's avatar
    tcarver committed
        c.gridy++;
    
        gridPanel.add(optionsBox, c);
        c.gridwidth = 1;
    
    tjc's avatar
    tjc committed
      }
      
    
    tcarver's avatar
    tcarver committed
      private void addTimeLastModified(GridBagConstraints c, JPanel gridPanel)
    
    tjc's avatar
    tjc committed
      {
        Qualifier timeQualifier = gffQualifiers.getQualifierByName("timelastmodified");
        if (timeQualifier != null)
        {
    
    tcarver's avatar
    tcarver committed
          JLabel timeLabel = new JLabel(timeQualifier.getValues().get(0));
    
    tjc's avatar
    tjc committed
          timeLabel.setEnabled(false);
          timeLabel.setToolTipText("time last modified");
          
    
    tcarver's avatar
    tcarver committed
          c.gridy++;
    
    tjc's avatar
    tjc committed
          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();  
    
    tcarver's avatar
    tcarver committed
        for(Qualifier qualifier: qualifiers) 
    
    tjc's avatar
    tjc committed
        {
    
    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
      }
    
      /**
    
    tcarver's avatar
    tcarver committed
       * Get the latest (edited) property qualifiers
    
    tjc's avatar
    tjc committed
       * @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 &&
    
    tcarver's avatar
    tcarver committed
            !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 &&
    
    tcarver's avatar
    tcarver committed
           !nameQualifier.getValues().get(0).equals(primaryNameTextField.getText())) ||
    
    tjc's avatar
    tjc committed
           (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
          {
    
    tcarver's avatar
    tcarver committed
            String oldPhase = phaseQualifier.getValues().get(0);
    
    tjc's avatar
    tjc committed
            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)
          {
    
    tcarver's avatar
    tcarver committed
            String isObsoleteOld = isObsoleteQualifier.getValues().get(0);
    
    tjc's avatar
    tjc committed
            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");
    
    tcarver's avatar
    tcarver committed
        String isObsoleteNew = isObsoleteQualifier.getValues().get(0);
        gffFeature.setVisible(!isObsoleteNew.equals("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)
      {
    
    tcarver's avatar
    tcarver committed
        return (synonymType.indexOf("systematic_id") > -1);
    
    tjc's avatar
    tjc committed
      }
    
      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();
    
    tcarver's avatar
    tcarver committed
    
    
    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,
    
    tcarver's avatar
    tcarver committed
             null, options, options[1]);
    
    tjc's avatar
    tjc committed
        
        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
        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
       */
    
    tcarver's avatar
    tcarver committed
      private void addPhaseComponent(final GridBagConstraints c, final JPanel gridPanel)
    
    tjc's avatar
    tjc committed
      {
        phaseButtonGroup = new ButtonGroup();
    
    tcarver's avatar
    tcarver committed
    
        JRadioButton phaseNone = new JRadioButton("Default", true);
    
    tjc's avatar
    tjc committed
        phaseNone.setOpaque(false);
        phaseNone.setActionCommand("");
        phaseButtonGroup.add(phaseNone);
    
    tcarver's avatar
    tcarver committed
        int codon_start = feature.getCodonStart();
           
    
    tjc's avatar
    tjc committed
        Box xBox = Box.createHorizontalBox();
    
        c.gridx = 0;
    
    tcarver's avatar
    tcarver committed
        c.gridy++;
    
    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);
    
    tcarver's avatar
    tcarver committed
    
        Qualifier qualifierCodonStart = gffQualifiers.getQualifierByName("codon_start");
        for(int i=1; i<4; i++)
        {
          String s = Integer.toString(i);
          JRadioButton phase = new JRadioButton(s);
          phase.setOpaque(false);
          phase.setActionCommand(s);
          phaseButtonGroup.add(phase);
          if(qualifierCodonStart != null && i == codon_start)
          {
            empty = false;
            phase.setSelected(true);
          }
          xBox.add(phase);
        }
    
    tjc's avatar
    tjc committed
        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
       */
      private void addSynonymComponent(final Qualifier qualifier, 
                                       final GridBagConstraints c, 
    
    tcarver's avatar
    tcarver committed
                                       final JPanel gridPanel)
    
    tjc's avatar
    tjc committed
      {
        empty = false;
        final StringVector values = qualifier.getValues();
    
        String name = qualifier.getName();
        if(name.equals("previous_systematic_id"))
          name = "prev_sys_id";
        final JLabel sysidField = new JLabel(name+" ");
        sysidField.setFont(getFont().deriveFont(Font.BOLD));
        sysidField.setHorizontalAlignment(SwingConstants.RIGHT);
        sysidField.setPreferredSize(calcPreferredLabelWidth());
    
    
        c.gridx = 0;
    
    tcarver's avatar
    tcarver committed
        c.gridy++;
    
    tjc's avatar
    tjc committed
        c.ipadx = 5;
    
        c.anchor = GridBagConstraints.EAST;
    
    tjc's avatar
    tjc committed
        gridPanel.add(sysidField, c);
    
    
        c.gridx = 1;
        c.anchor = GridBagConstraints.WEST;
    
        Box synBox = Box.createHorizontalBox();
    
    tcarver's avatar
    tcarver committed
        for (final String val: values)
    
    tcarver's avatar
    tcarver committed
          String strs[] = val.split(";");
          JLabel syn = new JLabel(" "+ strs[0] + ";");
    
          syn.setPreferredSize(calcPreferred(syn.getPreferredSize().width));
    
    tjc's avatar
    tjc committed
          
    
    tcarver's avatar
    tcarver committed
          if (strs.length > 1 && strs[1].indexOf("current=false") > -1)
    
            syn.setEnabled(false);
          synBox.add(syn);
    
    tcarver's avatar
    tcarver committed
    
    
          ActionListener removeAction = new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
              removeSynonym(qualifier.getName(), val);
            }  
          };
    
    tcarver's avatar
    tcarver committed
          synBox.add(new RemoveButton(removeAction));
    
    tjc's avatar
    tjc committed
        }
    
        c.gridwidth = GridBagConstraints.REMAINDER;
    
        gridPanel.add(synBox, c);
        c.gridwidth = 1;
    
    tjc's avatar
    tjc committed
      }
    
    tjc's avatar
    tjc committed
      public void featureChanged(FeatureChangeEvent event)
      {
        updateFromFeature(event.getFeature());
      }
    
    
      public boolean isEmpty()
      {
        return empty;
      }
    
    tjc's avatar
    tjc committed
      
      public void setObsoleteChanged(boolean obsoleteChanged)
      {
        obsoleteField.setSelected(obsoleteChanged);
      }
    
      private Dimension calcPreferredLabelWidth()
    
        int maxLabelWidth = new JLabel("prev_sys_id ").getPreferredSize().width;
        return calcPreferred(maxLabelWidth);
      }
      
      private Dimension calcPreferredMaxTextFieldWidth()
      {
        int maxLabelWidth = new JLabel("previous_systematic_id       ").getPreferredSize().width;
    
        return calcPreferred(maxLabelWidth);
    
      private Dimension calcPreferred(int w)
    
        FontMetrics fm = getFontMetrics(getFont());
    
        int preferredHeight = fm.getHeight()+fm.getDescent()+4;
    
        Dimension d = super.getPreferredSize();
        d.height = preferredHeight;
        d.width  = w;
        return d;
    
    tjc's avatar
    tjc committed
      
    
    tcarver's avatar
    tcarver committed
      protected void makeBorder()
    
    tjc's avatar
    tjc committed
      {
        Border grayline = BorderFactory.createLineBorder(Color.gray);
        setBorder(BorderFactory.createTitledBorder(grayline, 
            feature.getKey().getKeyString()));
      }
    
    tjc's avatar
    tjc committed
    }