Skip to content
Snippets Groups Projects
FeatureEdit.java 50.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* FeatureEdit.java
     *
     * created: Tue Dec  1 1998
     *
     * This file is part of Artemis
     *
     * Copyright (C) 1998,1999,2000,2001,2002  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/FeatureEdit.java,v 1.30 2007-03-19 10:15:03 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    package uk.ac.sanger.artemis.components;
    
    import uk.ac.sanger.artemis.util.*;
    import uk.ac.sanger.artemis.*;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.sequence.MarkerRange;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.DocumentEntry;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.OutOfDateException;
    import uk.ac.sanger.artemis.io.LocationParseException;
    import uk.ac.sanger.artemis.io.InvalidRelationException;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.QualifierLazyLoading;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.QualifierParseException;
    import uk.ac.sanger.artemis.io.Range;
    import uk.ac.sanger.artemis.io.RangeVector;
    import uk.ac.sanger.artemis.io.Key;
    import uk.ac.sanger.artemis.io.KeyVector;
    import uk.ac.sanger.artemis.io.Location;
    import uk.ac.sanger.artemis.io.Qualifier;
    import uk.ac.sanger.artemis.io.QualifierVector;
    import uk.ac.sanger.artemis.io.EntryInformation;
    import uk.ac.sanger.artemis.io.EntryInformationException;
    import uk.ac.sanger.artemis.io.StreamQualifier;
    import uk.ac.sanger.artemis.io.QualifierInfo;
    
    tjc's avatar
    tjc committed
    
    import uk.ac.sanger.artemis.components.ProgressThread;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.cv.CVPanel;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.gff.GffPanel;
    
    import uk.ac.sanger.artemis.components.genebuilder.ortholog.OrthologPanel;
    
    tjc's avatar
    tjc committed
    
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.util.Date;
    
    import java.util.Hashtable;
    
    tjc's avatar
    tjc committed
    import java.util.Vector;
    
    import java.util.Collections;
    import java.util.Comparator;
    
    tjc's avatar
    tjc committed
    import javax.swing.*;
    
    /**
     *  FeatureEdit class
     *
     *  @author Kim Rutherford
    
     *  @version $Id: FeatureEdit.java,v 1.30 2007-03-19 10:15:03 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    tjc's avatar
    tjc committed
    public class FeatureEdit extends JPanel
    
    tjc's avatar
    tjc committed
                             implements EntryChangeListener, FeatureChangeListener 
    {
    
    
    tjc's avatar
    tjc committed
      /**
       * 
       */
      private static final long serialVersionUID = 1L;
    
    
    tjc's avatar
    tjc committed
      /** Used to get current time/date in externalEdit(). */
      private static java.util.Calendar calendar =
                                   java.util.Calendar.getInstance();
    
      /** The choice of feature keys - created in createComponents(). */
      private KeyChoice key_choice;
    
      /** The choice of qualifiers - created in createComponents(). */
      private QualifierChoice qualifier_choice = null;
    
      private final static int LOCATION_TEXT_WIDTH = 80;
    
      /** The location text - set by updateLocation(). */
    
    tjc's avatar
    tjc committed
      private JTextField location_text = new JTextField(LOCATION_TEXT_WIDTH);
    
    tjc's avatar
    tjc committed
    
      /** When pressed - apply changes and dispose of the component. */
    
    tjc's avatar
    tjc committed
      private JButton ok_button = new JButton("OK");
    
    tjc's avatar
    tjc committed
    
      /** When pressed - discard changes and dispose of the component. */
    
    tjc's avatar
    tjc committed
      private JButton cancel_button = new JButton("Cancel");
    
    tjc's avatar
    tjc committed
    
      /** When pressed - apply changes and keep the component open. */
    
    tjc's avatar
    tjc committed
      private JButton apply_button = new JButton("Apply");
    
    tjc's avatar
    tjc committed
    
      /** Edit area for qualifiers - created by createComponents(). */
      private QualifierTextArea qualifier_text_area;
    
      /** The Feature this object is displaying. */
      private Feature edit_feature;
    
      /**
       *  The GotoEventSource that was passed to the constructor - used for the
       *  "Goto Feature" button.
       **/
      private GotoEventSource goto_event_source;
    
      /** Entry containing the Feature this object is displaying. */
      private Entry edit_entry;
    
      /** EntryGroup that contains this Feature (passed to the constructor). */
      private EntryGroup entry_group;
    
      /**
    
    tjc's avatar
    tjc committed
       *  The datestamp of the RWCorbaFeature when updateFromFeature() was last
    
    tjc's avatar
    tjc committed
       *  called or null if this is not a RWCorbaFeature.
       **/
      private Date datestamp = null;
    
      /** The Selection that was passed to the constructor. */
      private Selection selection;
    
      /**
       *  The contents of the QualifierTextArea before the user edits anything.
       *  This is used to work out if anything has changed since the creation of
       *  the FeatureEdit.
       **/
      final String orig_qualifier_text;
    
    
    tjc's avatar
    tjc committed
      private JFrame frame;
      
    
      /** controlled vocabulary tab */
    
    tjc's avatar
    tjc committed
      private CVPanel cvForm;
    
    tjc's avatar
    tjc committed
      
    
      /** GFF tab */
    
    tjc's avatar
    tjc committed
      private GffPanel gffPanel;
      
    
      /** ortholog/paralog tab */
      private OrthologPanel orthologForm;
      
      private EntryInformation entry_information;
      
    
    tjc's avatar
    tjc committed
      /**
       *  Create a new FeatureEdit object from the given Feature.
       *  @param entry_group The EntryGroup that contains this Feature.
       *  @param selection The Selection operate on.  The operations are "Remove
       *    Range" and "Grab Range"
    
    tjc's avatar
    tjc committed
       *  @param goto_event_source The object the we will call gotoBase() on.
    
    tjc's avatar
    tjc committed
       **/
    
    tjc's avatar
    tjc committed
      public FeatureEdit(final Feature edit_feature,
                         final EntryGroup entry_group,
                         final Selection selection,
    
    tjc's avatar
    tjc committed
                         final GotoEventSource goto_event_source,
                         final JFrame frame) 
    
    tjc's avatar
    tjc committed
      {
    
        this(edit_feature, entry_group, selection, 
             goto_event_source, frame, 
             edit_feature.getEntry().getEntryInformation());
      }
      
      public FeatureEdit(final Feature edit_feature,
          final EntryGroup entry_group,
          final Selection selection,
          final GotoEventSource goto_event_source,
          final JFrame frame, final EntryInformation entry_information) 
      {
        this.entry_information = entry_information;
    
    tjc's avatar
    tjc committed
        this.frame = frame;
    
    tjc's avatar
    tjc committed
        this.edit_feature = edit_feature;
    
    tjc's avatar
    tjc committed
        this.edit_entry   = edit_feature.getEntry();
    
    tjc's avatar
    tjc committed
        this.entry_group  = entry_group;
        this.selection    = selection;
    
    tjc's avatar
    tjc committed
        this.goto_event_source = goto_event_source;
    
    
    tjc's avatar
    tjc committed
        setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
        createComponents();
        updateFromFeature();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        orig_qualifier_text = qualifier_text_area.getText();
    
    tjc's avatar
    tjc committed
      
    
        if(edit_feature.getEntry() != null)
    
    tjc's avatar
    tjc committed
        {
    
          edit_feature.getEntry().addEntryChangeListener(this);
          edit_feature.addFeatureChangeListener(this);
    
    tjc's avatar
    tjc committed
    
    
          frame.addWindowListener(new WindowAdapter()
          {
            public void windowClosing(WindowEvent event)
            {
              stopListening();
              frame.dispose();
            }
          });
        }
        
    
    tjc's avatar
    tjc committed
        qualifier_text_area.requestFocus();
      }
    
    tjc's avatar
    tjc committed
      
      public void setActiveFeature(final Feature edit_feature)
      {
        this.edit_feature = edit_feature;
        this.edit_entry   = edit_feature.getEntry();
        updateFromFeature();
      }
    
    tjc's avatar
    tjc committed
    
      /**
       *  Remove this object as a feature and entry change listener.
       **/
    
    tjc's avatar
    tjc committed
      public void stopListening() 
      {
    
    tjc's avatar
    tjc committed
        getEntry().removeEntryChangeListener(this);
        getFeature().removeFeatureChangeListener(this);
    
    tjc's avatar
    tjc committed
        if(cvForm != null)
          getFeature().removeFeatureChangeListener(cvForm);
    
    tjc's avatar
    tjc committed
        if(gffPanel != null)
          getFeature().removeFeatureChangeListener(gffPanel);
    
        if(orthologForm != null)
          getFeature().removeFeatureChangeListener(orthologForm);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Implementation of the EntryChangeListener interface.  We listen to
       *  EntryChange events so we can notify the user if of this component if the
       *  feature gets deleted.
       **/
    
    tjc's avatar
    tjc committed
      public void entryChanged(EntryChangeEvent event) 
    
    tjc's avatar
    tjc committed
      {
        switch(event.getType())
        {
          case EntryChangeEvent.FEATURE_DELETED:
    
    tjc's avatar
    tjc committed
            if(event.getFeature() == edit_feature) 
    
    tjc's avatar
    tjc committed
            {
    
    tjc's avatar
    tjc committed
              stopListening();
    
    tjc's avatar
    tjc committed
              frame.dispose();
    
    tjc's avatar
    tjc committed
            }
            break;
          default:
            // do nothing;
            break;
    
    tjc's avatar
    tjc committed
        }
      }
    
      /**
       *  Add an ActionListener to the Cancel JButton of this FeatureEdit.
       **/
    
    tjc's avatar
    tjc committed
      public void addCancelActionListener(final ActionListener l) 
      {
        cancel_button.addActionListener(l);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Remove an ActionListener from the Cancel JButton of this FeatureEdit.
       **/
    
    tjc's avatar
    tjc committed
      public void removeCancelActionListener(final ActionListener l) 
      {
        cancel_button.removeActionListener(l);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Add an ActionListener to the Apply JButton of this FeatureEdit.
       **/
    
    tjc's avatar
    tjc committed
      public void addApplyActionListener(final ActionListener l) 
      {
    
    tjc's avatar
    tjc committed
        apply_button.addActionListener(l);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Remove an ActionListener from the Apply JButton of this FeatureEdit.
       **/
    
    tjc's avatar
    tjc committed
      public void removeApplyActionListener(final ActionListener l) 
      {
        apply_button.removeActionListener(l);
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Implementation of the FeatureChangeListener interface.  We need to
       *  listen to feature change events from the Features in this object so that
       *  we can update the display.
       *  @param event The change event.
       **/
    
    tjc's avatar
    tjc committed
      public void featureChanged(FeatureChangeEvent event) 
      {
    
    tjc's avatar
    tjc committed
        getFeature().resetColour();
    
    tjc's avatar
    tjc committed
        // re-read the information from the feature
    
    tjc's avatar
    tjc committed
        switch(event.getType()) 
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          case FeatureChangeEvent.LOCATION_CHANGED:
            updateLocation();
            break;
    
    tjc's avatar
    tjc committed
          case FeatureChangeEvent.SEGMENT_CHANGED:
            updateLocation();
            break;
    
    tjc's avatar
    tjc committed
          case FeatureChangeEvent.KEY_CHANGED:
            updateKey();
            break;
          case FeatureChangeEvent.QUALIFIER_CHANGED:
            if(qualifier_text_area.getText().equals(orig_qualifier_text)) 
              updateFromFeature();
            else
            {
              final String message =
                "warning: the qualifiers have changed outside the editor - " +
                "view now?";
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
              final YesNoDialog yes_no_dialog =
    
    tjc's avatar
    tjc committed
                new YesNoDialog(frame, message);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
              if(yes_no_dialog.getResult()) 
                new FeatureViewer(getFeature());
            }
            break;
          default:
            updateFromFeature();
            break;
    
    tjc's avatar
    tjc committed
        }
      }
    
    
      /**
       *  Create all the components for this FeatureEdit component.
       **/
    
    tjc's avatar
    tjc committed
      private void createComponents()
      {
    
    tjc's avatar
    tjc committed
        qualifier_text_area = new QualifierTextArea();
        qualifier_text_area.setWrapStyleWord(true);
    
    tjc's avatar
    tjc committed
    
        key_choice =
    
    tjc's avatar
    tjc committed
          new KeyChoice(getEntryInformation(),getFeature().getKey());
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel key_and_qualifier_panel = new JPanel();
        location_text.setBackground(Color.white);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel key_panel = new JPanel();
    
    tjc's avatar
    tjc committed
        key_panel.add(new JLabel("Key:"));
    
    tjc's avatar
    tjc committed
        key_panel.add(key_choice);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        key_and_qualifier_panel.setLayout(new BorderLayout());
        key_and_qualifier_panel.add(key_panel, "West");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        qualifier_choice = new QualifierChoice(getEntryInformation(),
    
    tjc's avatar
    tjc committed
                                      key_choice.getSelectedItem(),null);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel qualifier_panel = new JPanel();
        final JButton qualifier_add_button = new JButton("Add Qualifier:");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        qualifier_panel.add(qualifier_add_button);
        qualifier_panel.add(qualifier_choice);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        key_and_qualifier_panel.add(qualifier_panel, "East");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        key_choice.addItemListener(new ItemListener() 
        {
          public void itemStateChanged(ItemEvent _) 
          {
    
    tjc's avatar
    tjc committed
            qualifier_choice.setKey(key_choice.getSelectedItem());
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        qualifier_add_button.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent e)
          {
    
    tjc's avatar
    tjc committed
            final String qualifier_name =
    
    tjc's avatar
    tjc committed
              (String)qualifier_choice.getSelectedItem();
    
    tjc's avatar
    tjc committed
    
            QualifierInfo qualifier_info =
    
    tjc's avatar
    tjc committed
              getEntryInformation().getQualifierInfo(qualifier_name);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            if(qualifier_info == null) 
              qualifier_info = new QualifierInfo(qualifier_name,
                                  QualifierInfo.OPTIONAL_QUOTED_TEXT,
                                  null, null, false);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            qualifier_text_area.append("/" + qualifier_name);
    
    
    tjc's avatar
    tjc committed
            switch(qualifier_info.getType()) 
    
    tjc's avatar
    tjc committed
            {
              case QualifierInfo.QUOTED_TEXT:
                if(qualifier_name.equals("GO")) 
                {
                  // special case for /GO
                  final java.util.Calendar calendar =
                          java.util.Calendar.getInstance();
                    
    
    tjc's avatar
    tjc committed
                  final Date current_time = calendar.getTime();
    
    tjc's avatar
    tjc committed
                
    
    tjc's avatar
    tjc committed
                  final java.text.SimpleDateFormat date_format =
                      new java.text.SimpleDateFormat("yyyyMMdd");
    
    tjc's avatar
    tjc committed
                
    
    tjc's avatar
    tjc committed
                  final StringBuffer result_buffer = new StringBuffer();
    
    tjc's avatar
    tjc committed
                
    
    tjc's avatar
    tjc committed
                  date_format.format(current_time, result_buffer,
                                     new java.text.FieldPosition(java.text.DateFormat.DATE_FIELD));
    
    tjc's avatar
    tjc committed
                
    
    tjc's avatar
    tjc committed
                  final String go_string = "aspect=; term=; GOid=GO:; "+
                                           "evidence=ISS; db_xref=GOC:unpublished; " +
    
    tjc's avatar
    tjc committed
                                           "with=UniProt:; date=" + result_buffer;
    
    tjc's avatar
    tjc committed
                  qualifier_text_area.append("=\"" + go_string + "\"");
                } 
    
    tjc's avatar
    tjc committed
                else if(qualifier_name.equals("controlled_curation"))
                {
                  final java.util.Calendar calendar =
                          java.util.Calendar.getInstance();
    
                  final Date current_time = calendar.getTime();
    
                  final java.text.SimpleDateFormat date_format =
                      new java.text.SimpleDateFormat("yyyyMMdd");
    
                  final StringBuffer result_buffer = new StringBuffer();
    
                  date_format.format(current_time, result_buffer,
                                     new java.text.FieldPosition(java.text.DateFormat.DATE_FIELD));
    
                  final String cc_string = "term=; db_xref=; date="+ result_buffer;
                  qualifier_text_area.append("=\"" + cc_string + "\"");
                }
    
    tjc's avatar
    tjc committed
                else 
                  qualifier_text_area.append ("=\"\"");
                break;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
              case QualifierInfo.NO_VALUE:
              case QualifierInfo.OPTIONAL_QUOTED_TEXT:
                break;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
              default:
    
    tjc's avatar
    tjc committed
                qualifier_text_area.append("=");
    
    tjc's avatar
    tjc committed
            }
    
    
    tjc's avatar
    tjc committed
            qualifier_text_area.append("\n");
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        final JPanel middle_panel = new JPanel();
    
    tjc's avatar
    tjc committed
        middle_panel.setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel lower_panel = new JPanel();
    
    tjc's avatar
    tjc committed
        lower_panel.setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel outer_location_button_panel = new JPanel();
        lower_panel.add(outer_location_button_panel, "North");
        outer_location_button_panel.setLayout(new BorderLayout());
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel location_button_panel = new JPanel();
        outer_location_button_panel.add(location_button_panel, "West");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel location_panel = new JPanel();
        location_panel.setLayout(new BorderLayout());
        location_panel.add(new JLabel("location: "), "West");
    
    tjc's avatar
    tjc committed
        location_panel.add(location_text, "Center");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JButton complement_button = new JButton("Complement");
        location_button_panel.add(complement_button);
        complement_button.addActionListener(new ActionListener () 
        {
          public void actionPerformed(ActionEvent e) 
          {
            complementLocation();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        final JButton grab_button = new JButton("Grab Range");
        location_button_panel.add(grab_button);
        grab_button.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e)
          {
    
    tjc's avatar
    tjc committed
            grabSelectedRange();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        final JButton remove_button = new JButton("Remove Range");
        location_button_panel.add(remove_button);
        remove_button.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent e)
          {
            removeSelectedRange();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        final JButton goto_button = new JButton("Goto Feature");
        location_button_panel.add(goto_button);
    
    tjc's avatar
    tjc committed
        goto_button.addActionListener(new ActionListener() 
    
    tjc's avatar
    tjc committed
        {
          public void actionPerformed(ActionEvent e)
          {
            goto_event_source.gotoBase(getFeature().getFirstBaseMarker());
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        final JButton select_button = new JButton("Select Feature");
        location_button_panel.add(select_button);
        select_button.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e) 
          {
            getSelection().set(getFeature());
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        if(Options.getOptions().getPropertyTruthValue("sanger_options"))
    
    tjc's avatar
    tjc committed
        {
    
    tjc's avatar
    tjc committed
          // a PSU only hack 
    
    tjc's avatar
    tjc committed
          final JButton tidy_button = new JButton("Tidy");
          location_button_panel.add(tidy_button);
          tidy_button.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e) 
            {
              try 
              {
    
    tjc's avatar
    tjc committed
                tidy();
    
                tidyGO();
    
    tjc's avatar
    tjc committed
              } 
    
    tjc's avatar
    tjc committed
              catch(QualifierParseException exception) 
    
    tjc's avatar
    tjc committed
              {
                final String error_string = exception.getMessage();
    
    tjc's avatar
    tjc committed
                new MessageDialog(frame,
    
    tjc's avatar
    tjc committed
                                  "Cannot tidy - qualifier error: " +
                                  error_string);
    
    tjc's avatar
    tjc committed
              }
            }
          });
        }
    
    
    tjc's avatar
    tjc committed
        if(Options.getOptions().getProperty("external_editor") != null)
        {
          final JButton external_fasta_edit_button = new JButton("MESS/FASTA");
          location_button_panel.add(external_fasta_edit_button);
          external_fasta_edit_button.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e) 
            {
              try 
              {
                if(getFeature().getQualifierByName("fasta_file") != null) 
                {
    
    tjc's avatar
    tjc committed
                  final String DEFAULT_MAX_EUK_FASTA_HITS = "10";
                  final String max_fasta_hits;
    
                  final String max_fasta_hits_from_options =
    
    tjc's avatar
    tjc committed
                    Options.getOptions().getProperty("mess_fasta_hits");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
                  if(Options.getOptions().isEukaryoticMode()) 
                  {
                    if (max_fasta_hits_from_options == null) 
    
    tjc's avatar
    tjc committed
                      max_fasta_hits = DEFAULT_MAX_EUK_FASTA_HITS;
    
    tjc's avatar
    tjc committed
                    else 
    
    tjc's avatar
    tjc committed
                      max_fasta_hits = max_fasta_hits_from_options;
    
    
    tjc's avatar
    tjc committed
                    externalEdit(new String[] { "-fasta", "-maxhits",
                                                max_fasta_hits, "-euk" });
    
    tjc's avatar
    tjc committed
                  } 
                  else 
                  {
                    if(max_fasta_hits_from_options == null) 
                    {
    
    tjc's avatar
    tjc committed
                      externalEdit(new String[] { "-fasta" });
    
    tjc's avatar
    tjc committed
                    } 
                    else 
                    {
    
    tjc's avatar
    tjc committed
                      externalEdit(new String[] { "-fasta", "-maxhits",
                                                  max_fasta_hits_from_options });
    
    tjc's avatar
    tjc committed
                    }
                  }
                  return;
                }
    
    tjc's avatar
    tjc committed
              } catch(InvalidRelationException _) {}
    
    tjc's avatar
    tjc committed
              
    
    tjc's avatar
    tjc committed
              new MessageDialog(frame,
    
    tjc's avatar
    tjc committed
                                "nothing to edit - no /fasta_file qualifier");
    
    tjc's avatar
    tjc committed
            }
          });
    
    
    tjc's avatar
    tjc committed
          final JButton external_blastp_edit_button = new JButton("MESS/BLASTP");
          location_button_panel.add(external_blastp_edit_button);
          external_blastp_edit_button.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e) 
            {
              try 
              {
                if(getFeature().getQualifierByName("blastp_file") != null)
                {
    
    tjc's avatar
    tjc committed
                  final String DEFAULT_MAX_BLASTP_HITS = "10";
                  final String max_blastp_hits;
    
                  final String max_blastp_hits_from_options =
    
    tjc's avatar
    tjc committed
                    Options.getOptions().getProperty("mess_blastp_hits");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
                  if(max_blastp_hits_from_options == null) 
    
    tjc's avatar
    tjc committed
                    max_blastp_hits = DEFAULT_MAX_BLASTP_HITS;
    
    tjc's avatar
    tjc committed
                  else 
    
    tjc's avatar
    tjc committed
                    max_blastp_hits = max_blastp_hits_from_options;
    
    
    tjc's avatar
    tjc committed
                  if(Options.getOptions().isEukaryoticMode()) 
                  {
    
    tjc's avatar
    tjc committed
                    externalEdit(new String[] { "-blastp", "-maxhits",
                                                max_blastp_hits, "-euk" });
    
    tjc's avatar
    tjc committed
                  } 
                  else
                  {
    
    tjc's avatar
    tjc committed
                    externalEdit(new String[] { "-blastp", "-maxhits",
                                                max_blastp_hits });
    
    tjc's avatar
    tjc committed
                  }
                  return;
                }
    
    tjc's avatar
    tjc committed
              } catch(InvalidRelationException _) {}
              
    
    tjc's avatar
    tjc committed
              new MessageDialog(frame,
    
    tjc's avatar
    tjc committed
                                "nothing to edit - no /blastp_file qualifier");
    
    tjc's avatar
    tjc committed
            }
          });
    
    
    tjc's avatar
    tjc committed
          final JButton external_go_edit_button = new JButton("MESS/GO");
          location_button_panel.add(external_go_edit_button);
          external_go_edit_button.addActionListener(new ActionListener () 
          {
            public void actionPerformed(ActionEvent e) 
            {
              try
              {
                if(getFeature().getQualifierByName("blastp+go_file") != null) 
                {
    
    tjc's avatar
    tjc committed
                  final String DEFAULT_MAX_GO_BLAST_HITS = "10";
                  final String max_go_blast_hits;
    
                  final String max_go_blast_hits_from_options =
                    Options.getOptions ().getProperty ("mess_blast_go_hits");
    
    
    tjc's avatar
    tjc committed
                  if (max_go_blast_hits_from_options == null) 
    
    tjc's avatar
    tjc committed
                    max_go_blast_hits = DEFAULT_MAX_GO_BLAST_HITS;
    
    tjc's avatar
    tjc committed
                  else 
    
    tjc's avatar
    tjc committed
                    max_go_blast_hits = max_go_blast_hits_from_options;
    
    
    tjc's avatar
    tjc committed
                  if(Options.getOptions().isEukaryoticMode()) 
                  {
    
    tjc's avatar
    tjc committed
                    externalEdit(new String[] { "-blastp+go", "-maxhits",
                                                max_go_blast_hits, "-euk" });
    
    tjc's avatar
    tjc committed
                  } 
                  else
                  {
    
    tjc's avatar
    tjc committed
                    externalEdit(new String[] { "-blastp+go", "-maxhits",
                                                max_go_blast_hits });
    
    tjc's avatar
    tjc committed
                  }
                  return;
                }
    
    tjc's avatar
    tjc committed
              } catch(InvalidRelationException _) {}
    
    tjc's avatar
    tjc committed
              
    
    tjc's avatar
    tjc committed
              new MessageDialog(frame,
    
    tjc's avatar
    tjc committed
                                "nothing to edit - no /blastp+go_file qualifier");
    
    tjc's avatar
    tjc committed
            }
          });
        }
    
    
    tjc's avatar
    tjc committed
        if(Options.isUnixHost())
        {
          JButton oo_edit_button = new JButton("ObjectEdit");
          location_button_panel.add(oo_edit_button);
    
          final uk.ac.sanger.artemis.editor.BigPane bp =
                                 new uk.ac.sanger.artemis.editor.BigPane();
    
    
    tjc's avatar
    tjc committed
          oo_edit_button.addActionListener(new ActionListener ()
          {
            public void actionPerformed(ActionEvent e)
            {
              String qualifier_txt = qualifier_text_area.getText();
            
    
    tjc's avatar
    tjc committed
              File base_dir = getBaseDirectoryFromEntry(edit_entry);
              String baseDirStr = "";
    
              if(base_dir != null)
                baseDirStr = base_dir.getAbsolutePath() + 
                                  System.getProperty("file.separator");
    
    
    tjc's avatar
    tjc committed
              StringReader strRead = new StringReader(qualifier_txt);
              BufferedReader buff = new BufferedReader(strRead);
              String line;
    
              final Hashtable dataFile = new Hashtable();
    
    tjc's avatar
    tjc committed
              try
              {
                while((line = buff.readLine()) != null)
                {
                  if(line.startsWith("/fasta_file="))
                  {
                    int ind = line.lastIndexOf("\"");
                    if(ind > -1)
    
                      dataFile.put("fasta", baseDirStr+line.substring(13,ind));
    
    tjc's avatar
    tjc committed
                  }
                  else if(line.startsWith("/blastp_file="))
                  {
                    int ind = line.lastIndexOf("\"");
                    if(ind > -1)
    
                      dataFile.put("blastp", baseDirStr+line.substring(14,ind));
    
    tjc's avatar
    tjc committed
                  }
                  else if(line.startsWith("/blastp+go_file="))
                  {
                    int ind = line.lastIndexOf("\"");
                    if(ind > -1)
    
                      dataFile.put("blastp+go", baseDirStr+line.substring(17,ind));
    
    tjc's avatar
    tjc committed
                  }   
                }
              }
              catch(IOException ioe){}
     
              FeatureEdit.this.setCursor(new Cursor(Cursor.WAIT_CURSOR)); 
              final ProgressThread progress = new ProgressThread(null,
                                            "Loading Data....");
              progress.start();
              SwingWorker ooEd = new SwingWorker()
              {
                public Object construct()
                {
    
    tjc's avatar
    tjc committed
                  // find overlaping features
    
    tjc's avatar
    tjc committed
                  final Location this_loc = edit_feature.getLocation();
    
    tjc's avatar
    tjc committed
                  final int this_start = this_loc.getFirstBase();
                  final int this_end   = this_loc.getLastBase();
    
                  FeaturePredicate predicate = new FeaturePredicate()
                  {
                    public boolean testPredicate (final Feature feature) 
                    {
    
    tjc's avatar
    tjc committed
                      final Location loc = feature.getLocation();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
                      final int start = loc.getFirstBase();
                      final int end   = loc.getLastBase();
    
    tjc's avatar
    tjc committed
    
                      if((start > this_start &&
                          start < this_end) ||
                         (end > this_start &&
                          end < this_end))
                      {
    
    tjc's avatar
    tjc committed
                        final String note = feature.getNote();
    
    tjc's avatar
    tjc committed
                        if(note != null &&
                           note.indexOf("Pfam")>-1)
    
    tjc's avatar
    tjc committed
                          return true;
                      }
                      
                      return false;
                    }
                  };
    
    
    tjc's avatar
    tjc committed
                  final FeatureVector overlapFeatures = new FeatureVector();
                  final FeatureEnumeration featureEnum = entry_group.features();
    
    tjc's avatar
    tjc committed
                  while(featureEnum.hasMoreFeatures()) 
                  {
                    Feature this_feature = featureEnum.nextFeature();
                    if(predicate.testPredicate(this_feature))
                      overlapFeatures.add(this_feature);
                  }
    
                  // show object editor
    
                   bp.set(dataFile, qualifier_text_area, overlapFeatures,
    
                  }
                  catch(ArrayIndexOutOfBoundsException e)
                  {
                    JOptionPane.showMessageDialog(null,"No results files.",
                            "Warning",
                            JOptionPane.WARNING_MESSAGE);
                  }
    
    
    tjc's avatar
    tjc committed
                  progress.finished();
                  FeatureEdit.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                  return null;
                }
              };
              ooEd.start();   
            }
          });
        }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        middle_panel.add(location_panel, "North");
    
    tjc's avatar
    tjc committed
        add(key_and_qualifier_panel, "North");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        cancel_button.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent e) 
          {
    
            if(edit_feature.getEntry() != null)
              stopListening();
    
    tjc's avatar
    tjc committed
            frame.dispose();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
    tjc's avatar
    tjc committed
        if(!getFeature().isReadOnly())
        {
          ok_button.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent e)
            {
              if(setFeature()) 
              {
                stopListening();
    
    tjc's avatar
    tjc committed
                frame.dispose();
    
    tjc's avatar
    tjc committed
              }
            }
          });
    
    
    tjc's avatar
    tjc committed
          apply_button.addActionListener(new ActionListener() 
          {
            public void actionPerformed(ActionEvent e) 
            {
              setFeature();
    
    tjc's avatar
    tjc committed
            }
          });
        }
    
        final FlowLayout flow_layout =
    
    tjc's avatar
    tjc committed
                     new FlowLayout(FlowLayout.CENTER, 18, 5);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JPanel ok_cancel_update_panel = new JPanel(flow_layout);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(!getFeature().isReadOnly()) 
    
    tjc's avatar
    tjc committed
          ok_cancel_update_panel.add(ok_button);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        ok_cancel_update_panel.add(cancel_button);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(!getFeature().isReadOnly()) 
    
    tjc's avatar
    tjc committed
          ok_cancel_update_panel.add(apply_button);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        add(ok_cancel_update_panel, "South");
    
    tjc's avatar
    tjc committed
    
    
        if(((DocumentEntry)getFeature().getEmblFeature().getEntry()).getDocument() 
    
    tjc's avatar
    tjc committed
            instanceof DatabaseDocument)
        {
          cvForm = new CVPanel(getFeature());
    
          // tabbed pane of core and cv annotaion
          JTabbedPane tabbedPane = new JTabbedPane();
    
    tjc's avatar
    tjc committed
          
    
    tjc's avatar
    tjc committed
          JScrollPane jspCore = new JScrollPane(qualifier_text_area);
    
    tjc's avatar
    tjc committed
          tabbedPane.add("Core", jspCore);
    
    
    tjc's avatar
    tjc committed
          JScrollPane jspCV   = new JScrollPane(cvForm);
          jspCV.setPreferredSize(jspCore.getPreferredSize());
          tabbedPane.add("CV", jspCV);
    
    tjc's avatar
    tjc committed
          
    
          orthologForm = new OrthologPanel(getFeature());
          JScrollPane jspOrtholog   = new JScrollPane(orthologForm);
          jspCV.setPreferredSize(jspOrtholog.getPreferredSize());
          tabbedPane.add("Ortholog", jspOrtholog);
          
    
    tjc's avatar
    tjc committed
          gffPanel = new GffPanel(getFeature());
          JScrollPane jspGff = new JScrollPane(gffPanel);
          jspGff.setPreferredSize(jspCore.getPreferredSize());
          tabbedPane.add("GFF", jspGff);
          
    
    tjc's avatar
    tjc committed
          lower_panel.add(tabbedPane, "Center");
        }
        else
          lower_panel.add(new JScrollPane(qualifier_text_area), "Center");
        
    
    tjc's avatar
    tjc committed
        middle_panel.add(lower_panel, "Center");
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        add(middle_panel, "Center");
    
    tjc's avatar
    tjc committed
      }
    
    
    tjc's avatar
    tjc committed
    
      /**
       *  Return the dirtectory that the given entry was read from.
       **/
      private File getBaseDirectoryFromEntry(final Entry entry)
      {
        final uk.ac.sanger.artemis.io.Entry embl_entry = entry.getEMBLEntry();
    
        if(embl_entry instanceof DocumentEntry)
        {
          final DocumentEntry document_entry =(DocumentEntry) embl_entry;
    
          if(document_entry.getDocument() instanceof FileDocument)
          {
            final FileDocument file_document =
             (FileDocument) document_entry.getDocument();
    
            if(file_document.getFile().getParent() != null)
              return new File(file_document.getFile().getParent());
          }
        }
    
        return null;
      }
    
    
    tjc's avatar
    tjc committed
      /**
       *  Read the key, location and qualifier information from the feature and
       *  update the components.
       **/
    
    tjc's avatar
    tjc committed
      private void updateFromFeature() 
      {
        datestamp = getFeature().getDatestamp();
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        updateKey();
        updateLocation();
        updateQualifiers();
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Read the location from the feature and update the location field.
       **/
    
    tjc's avatar
    tjc committed
      private void updateLocation() 
      {
        location_text.setText(getFeature().getLocation().toStringShort());
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *   Complement the current location_text.
       **/
    
    tjc's avatar
    tjc committed
      private void complementLocation() 
      {
        if(rationalizeLocation()) 
        {
          if(location_text.getText().startsWith("complement(")) 
          {
            final String new_text = location_text.getText().substring(11);
    
    tjc's avatar
    tjc committed
            if (new_text.endsWith(")")) 
    
    tjc's avatar
    tjc committed
            {
    
    tjc's avatar
    tjc committed
              final String new_text2 =
    
    tjc's avatar
    tjc committed
                new_text.substring(0, new_text.length () - 1);
              location_text.setText(new_text2);
    
    tjc's avatar
    tjc committed
            } 
            else 
    
    tjc's avatar
    tjc committed
              location_text.setText(new_text);
    
    tjc's avatar
    tjc committed
          }
          else 
          {
    
    tjc's avatar
    tjc committed
            final String new_text = location_text.getText ();
    
    tjc's avatar
    tjc committed
            location_text.setText("complement(" + new_text + ")");
    
    tjc's avatar
    tjc committed
          }
    
    tjc's avatar
    tjc committed
        } 
        else 
    
    tjc's avatar
    tjc committed
          new MessageDialog(frame, "complement failed - " +
    
    tjc's avatar
    tjc committed
                            "current location cannot be parsed");
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Tidy the qualifiers by removing any indication that the annotation has
       *  been transferred from another gene.  Remove the "transferred_" part of
       *  all qualifier names and the "[[FROM sc_001234 abc1]]" bit of each
       *  corresponding qualifier value.
       **/
    
    tjc's avatar
    tjc committed
      private void tidy() throws QualifierParseException
      {
        final StringBuffer buffer = new StringBuffer();
    
    tjc's avatar
    tjc committed
    
        final QualifierVector qualifiers =
    
    tjc's avatar
    tjc committed
          qualifier_text_area.getParsedQualifiers(getEntryInformation());
    
    tjc's avatar
    tjc committed
        
    
    tjc's avatar
    tjc committed
        for(int qualifier_index = 0; qualifier_index < qualifiers.size();
             ++qualifier_index) 
        {
    
    tjc's avatar
    tjc committed
          final Qualifier this_qualifier = (Qualifier)qualifiers.elementAt(qualifier_index);
    
    tjc's avatar
    tjc committed
          
          final QualifierInfo qualifier_info =
    
    tjc's avatar
    tjc committed
                getEntryInformation().getQualifierInfo(this_qualifier.getName());
    
    tjc's avatar
    tjc committed
          
          final StringVector qualifier_strings =
    
    tjc's avatar
    tjc committed
              StreamQualifier.toStringVector(qualifier_info, this_qualifier);
    
    tjc's avatar
    tjc committed
          
    
    tjc's avatar
    tjc committed
          for(int value_index = 0; value_index < qualifier_strings.size();
              ++value_index)
          {
    
    tjc's avatar
    tjc committed
            final String qualifier_string =
    
    tjc's avatar
    tjc committed
              (String)qualifier_strings.elementAt(value_index);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            buffer.append(tidyHelper(qualifier_string) + "\n");
    
    tjc's avatar
    tjc committed
          }
        }
    
    
    tjc's avatar
    tjc committed
        qualifier_text_area.setText(buffer.toString());
    
    tjc's avatar
    tjc committed
      }
    
    
      private void tidyGO() throws QualifierParseException
      {
        String qualifier_txt = qualifier_text_area.getText();
        StringReader strRead = new StringReader(qualifier_txt);
        BufferedReader buff = new BufferedReader(strRead);
        String line;
        final Vector qual_str = new Vector();
        try
        {
          while((line = buff.readLine()) != null)
            qual_str.add(line);
        }
        catch(IOException ioe){}
    
        Comparator comparator = new Comparator()
        {
          public int compare (Object fst, Object snd)
          {