Skip to content
Snippets Groups Projects
AddMenu.java 59.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* AddMenu.java
     *
     * created: Tue Dec 29 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/AddMenu.java,v 1.42 2009-06-01 09:49:07 tjc Exp $
    
    tjc's avatar
    tjc committed
     */
    
    package uk.ac.sanger.artemis.components;
    
    import uk.ac.sanger.artemis.*;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.plot.CodonUsageAlgorithm;
    
    
    import uk.ac.sanger.artemis.sequence.BasePattern;
    import uk.ac.sanger.artemis.sequence.BasePatternFormatException;
    import uk.ac.sanger.artemis.sequence.Bases;
    import uk.ac.sanger.artemis.sequence.MarkerRange;
    import uk.ac.sanger.artemis.sequence.MarkerRangeVector;
    import uk.ac.sanger.artemis.sequence.Strand;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.*;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.DatabaseDocumentEntry;
    
    import uk.ac.sanger.artemis.io.GFFStreamFeature;
    
    import uk.ac.sanger.artemis.io.InvalidRelationException;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.Key;
    import uk.ac.sanger.artemis.io.Range;
    import uk.ac.sanger.artemis.io.RangeVector;
    import uk.ac.sanger.artemis.io.Location;
    import uk.ac.sanger.artemis.io.QualifierVector;
    import uk.ac.sanger.artemis.io.Qualifier;
    import uk.ac.sanger.artemis.io.LocationParseException;
    import uk.ac.sanger.artemis.io.EntryInformationException;
    
    
    import java.awt.Cursor;
    import java.awt.Toolkit;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    import java.util.Comparator;
    
    import java.util.Vector;
    import java.util.Enumeration;
    
    tjc's avatar
    tjc committed
    import java.util.regex.Pattern;
    
    
    import javax.swing.Box;
    import javax.swing.JCheckBox;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JMenuItem;
    import javax.swing.JOptionPane;
    import javax.swing.JTextField;
    import javax.swing.KeyStroke;
    
    
    tjc's avatar
    tjc committed
    
    /**
     *  A Menu with commands that add new features/entries to an EntryGroup.  This
     *  should have been called CreateMenu.
     *
     *  @author Kim Rutherford
    
     *  @version $Id: AddMenu.java,v 1.42 2009-06-01 09:49:07 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    public class AddMenu extends SelectionMenu 
    {
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
      private static final long serialVersionUID = 1L;
    
    
    tjc's avatar
    tjc committed
      /** The GotoEventSource object that was passed to the constructor. */
      private GotoEventSource goto_event_source = null;
    
      /** The EntryGroup object that was passed to the constructor. */
      private EntryGroup entry_group;
    
      private BasePlotGroup base_plot_group;
      
    
    tjc's avatar
    tjc committed
      /**
       *  The shortcut for "Create From Base Range".
       **/
      final static KeyStroke CREATE_FROM_BASE_RANGE_KEY =
    
        KeyStroke.getKeyStroke (KeyEvent.VK_C,
                                Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); //InputEvent.CTRL_MASK);
    
    tjc's avatar
    tjc committed
    
      final static public int CREATE_FROM_BASE_RANGE_KEY_CODE = KeyEvent.VK_C;
    
    
    tjc's avatar
    tjc committed
      /** busy cursor */
      private Cursor cbusy = new Cursor(Cursor.WAIT_CURSOR);
      /** done cursor */
      private Cursor cdone = new Cursor(Cursor.DEFAULT_CURSOR);
    
    
    tjc's avatar
    tjc committed
      /*private AlignmentViewer alignQueryViewer;
      private AlignmentViewer alignSubjectViewer;*/
    
    tjc's avatar
    tjc committed
      /**
       *  Create a new AddMenu object.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param entry_group The EntryGroup object where new features/entries will
       *    be added.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
    
       *  @param base_plot_group The AlignmentViewer associated with this JMenu
       *
    
    tjc's avatar
    tjc committed
       *  @param menu_name The name of the new menu.
       **/
      public AddMenu (final JFrame frame,
                      final Selection selection,
                      final EntryGroup entry_group,
                      final GotoEventSource goto_event_source,
                      final BasePlotGroup base_plot_group,
    
                      final String menu_name) 
      {
        this(frame,selection,entry_group,
    
    tjc's avatar
    tjc committed
             goto_event_source,base_plot_group,null,null,menu_name);
    
      }
    
      /**
       *  Create a new AddMenu object.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param entry_group The EntryGroup object where new features/entries will
       *    be added.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
       *  @param menu_name The name of the new menu.
       **/
      public AddMenu(final JFrame frame,
                     final Selection selection,
                     final EntryGroup entry_group,
                     final GotoEventSource goto_event_source,
                     final BasePlotGroup base_plot_group,
    
    tjc's avatar
    tjc committed
                     final AlignmentViewer alignQueryViewer, 
                     final AlignmentViewer alignSubjectViewer,
                     final String menu_name)
    
    tjc's avatar
    tjc committed
        super (frame, menu_name, selection);
    
    
    tjc's avatar
    tjc committed
        /*this.alignQueryViewer   = alignQueryViewer;
        this.alignSubjectViewer = alignSubjectViewer;*/
    
    tjc's avatar
    tjc committed
        this.entry_group = entry_group;
        this.base_plot_group = base_plot_group;
    
    
    tjc's avatar
    tjc committed
        final JMenuItem new_feature_item = new JMenuItem ("New Feature");
    
    tjc's avatar
    tjc committed
        new_feature_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            makeNewFeature ();
          }
        });
    
        add (new_feature_item);
    
    
    tjc's avatar
    tjc committed
        final JMenuItem create_feature_from_range_item =
    
    tjc's avatar
    tjc committed
          new JMenuItem ("Feature From Base Range");
    
        
        if(!GeneUtils.isDatabaseEntry(entry_group))
          create_feature_from_range_item.setAccelerator (CREATE_FROM_BASE_RANGE_KEY);
    
    tjc's avatar
    tjc committed
        create_feature_from_range_item.addActionListener(new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            createFeatureFromBaseRange (getParentFrame (), getSelection (),
                                        entry_group, getGotoEventSource ());
          }
        });
    
        add (create_feature_from_range_item);
    
    tjc's avatar
    tjc committed
        
        
        if(GeneUtils.isDatabaseEntry(entry_group))
        {
          final JMenuItem create_gene_model_from_range_item = new JMenuItem(
    
    tjc's avatar
    tjc committed
              "Gene Model From Base Range");
    
          create_gene_model_from_range_item.setAccelerator(CREATE_FROM_BASE_RANGE_KEY);
    
    tjc's avatar
    tjc committed
          create_gene_model_from_range_item.addActionListener(new ActionListener()
          {
            public void actionPerformed(ActionEvent event)
            {
    
    tjc's avatar
    tjc committed
              entry_group.getActionController ().startAction ();
    
    tjc's avatar
    tjc committed
              GeneUtils.createGeneModel(getParentFrame(), getSelection(),
                  entry_group, getGotoEventSource());
    
    tjc's avatar
    tjc committed
              entry_group.getActionController ().endAction ();
    
    tjc's avatar
    tjc committed
            }
          });
          add (create_gene_model_from_range_item);
        }
    
        add (create_feature_from_range_item);
        
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        if(alignQueryViewer != null || alignSubjectViewer != null)
    
        {
          JMenuItem create_difference_feature  =
    
    tjc's avatar
    tjc committed
            new JMenuItem("Features From Non-matching Regions");
    
          create_difference_feature.addActionListener(new ActionListener()
          {
            public void actionPerformed (ActionEvent event) 
            {
    
    tjc's avatar
    tjc committed
              frame.setCursor(cbusy);
    
              Vector diffs = null;
    
              String comparisonNote = "";
    
              if(alignQueryViewer == null || alignSubjectViewer == null)
    
                final Entry sequence_entry;
    
                if(alignQueryViewer != null)
    
                  diffs = alignQueryViewer.getDifferenceCoords(false);
    
                  sequence_entry = alignQueryViewer.getSubjectEntryGroup().getSequenceEntry();
                }
    
                  diffs = alignSubjectViewer.getDifferenceCoords(true);
    
                  sequence_entry = alignSubjectViewer.getQueryEntryGroup().getSequenceEntry();
                }
    
                comparisonNote = comparisonNote + sequence_entry.getName();
    
              }
              else    // multi-comparison
              {
                Vector diffs1 = alignQueryViewer.getDifferenceCoords(false);
                Vector diffs2 = alignSubjectViewer.getDifferenceCoords(true);
    
              
                Entry sequence_entry;
                sequence_entry = alignQueryViewer.getSubjectEntryGroup().getSequenceEntry();
                comparisonNote = comparisonNote + sequence_entry.getName();
    
                sequence_entry = alignSubjectViewer.getQueryEntryGroup().getSequenceEntry();
                comparisonNote = comparisonNote + " and " + sequence_entry.getName();
      
    
                diffs = union(diffs1,diffs2);
    
              
              createFeatures(diffs, frame, comparisonNote);
    
    tjc's avatar
    tjc committed
              frame.setCursor(cdone);
    
            }
          });
    
          add (create_difference_feature);
        }
    
    
    tjc's avatar
    tjc committed
        final JMenuItem create_intron_features_item =
    
    tjc's avatar
    tjc committed
          new JMenuItem ("Intron Features");
    
    tjc's avatar
    tjc committed
        create_intron_features_item.addActionListener(new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            createIntronFeatures (getParentFrame (), getSelection (),
                                  entry_group);
          }
        });
    
    tjc's avatar
    tjc committed
        add (create_intron_features_item);
    
        if(GeneUtils.isDatabaseEntry(entry_group))
    
          create_intron_features_item.setEnabled(false);
    
        
        final JMenuItem create_intergenic_features_item =
    
    tjc's avatar
    tjc committed
          new JMenuItem ("Intergenic Features");
    
        create_intergenic_features_item.addActionListener(new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            createIntergenicFeatures(getParentFrame (), entry_group);
          }
        });
        add (create_intergenic_features_item);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JMenuItem create_exon_features_item =
    
    tjc's avatar
    tjc committed
          new JMenuItem ("Exon Features");
    
    tjc's avatar
    tjc committed
        create_exon_features_item.addActionListener(new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            createExonFeatures (getParentFrame (), getSelection (),
                                entry_group);
          }
        });
    
        add (create_exon_features_item);
    
        if(GeneUtils.isDatabaseEntry(entry_group))
    
          create_exon_features_item.setEnabled(false);
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        final JMenuItem create_gene_features_item =
    
    tjc's avatar
    tjc committed
          new JMenuItem ("Gene Features");
    
    tjc's avatar
    tjc committed
        create_gene_features_item.addActionListener(new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            createGeneFeatures (getParentFrame (), getSelection (),
                                entry_group);
          }
        });
    
        add (create_gene_features_item);
    
        if(GeneUtils.isDatabaseEntry(entry_group))
    
          create_gene_features_item.setEnabled(false);
    
    tjc's avatar
    tjc committed
    
        addSeparator ();
    
    
    tjc's avatar
    tjc committed
        final JMenuItem new_entry_item = new JMenuItem ("New Entry");
    
    tjc's avatar
    tjc committed
        new_entry_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            makeNewEntry ();
          }
        });
    
        add (new_entry_item);
    
        addSeparator ();
    
    
    tjc's avatar
    tjc committed
        final JMenuItem mark_orfs_with_size_item = new JMenuItem ("Mark Open Reading Frames ...");
    
    tjc's avatar
    tjc committed
    
        mark_orfs_with_size_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
    
    tjc's avatar
    tjc committed
            markORFSWithSize (false, frame);
    
    tjc's avatar
    tjc committed
          }
        });
    
        add (mark_orfs_with_size_item);
    
    
    
    tjc's avatar
    tjc committed
        final JMenuItem mark_empty_orfs_with_size_item = new JMenuItem ("Mark Empty ORFs ...");
    
    tjc's avatar
    tjc committed
    
        mark_empty_orfs_with_size_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
    
    tjc's avatar
    tjc committed
            markORFSWithSize (true, frame);
    
    tjc's avatar
    tjc committed
          }
        });
    
        add (mark_empty_orfs_with_size_item);
    
    
    
    tjc's avatar
    tjc committed
        final JMenuItem mark_orfs_range_item = new JMenuItem ("Mark ORFs In Range ...");
    
    tjc's avatar
    tjc committed
        mark_orfs_range_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            markOpenReadingFramesInRange ();
          }
        });
    
        add (mark_orfs_range_item);
    
    
    
    tjc's avatar
    tjc committed
        final JMenuItem mark_pattern_item = new JMenuItem ("Mark From Pattern ...");
    
    tjc's avatar
    tjc committed
        mark_pattern_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            makeFeaturesFromPattern ();
          }
        });
    
        add (mark_pattern_item);
    
    
    tjc's avatar
    tjc committed
        final JMenuItem mark_ambiguities_item = new JMenuItem ("Mark Ambiguities");
    
    tjc's avatar
    tjc committed
        mark_ambiguities_item.addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent event) {
            markAmbiguities ();
          }
        });
    
        add (mark_ambiguities_item);
      }
    
    
      /**
      *
      * Find the union of coordinates in two Vecor objects.
      * @param v1 Vector of Integer coordinates
      * @param v2 Vector of Integer coordinates
      *  
      */
    
    tjc's avatar
    tjc committed
      protected static Vector union(final Vector v1, final Vector v2)
    
    tjc's avatar
    tjc committed
        final Vector union = new Vector();
    
    
        for(int i=0; i<v1.size(); i++)
        {
          Integer[] imatch = (Integer[])v1.get(i);
          int istart = imatch[0].intValue();
          int iend   = imatch[1].intValue();
    
          for(int j=0; j<v2.size(); j++)
          {
            Integer[] jmatch = (Integer[])v2.get(j);
            int jstart = jmatch[0].intValue();
            int jend   = jmatch[1].intValue();
    
            if( (istart >= jstart && istart <= jend) ||
                (iend >= jstart && iend <= jend) ||
                (jstart > istart && jend < iend) )
            {
              if(jstart > istart)
                istart = jstart;
              
              if(iend < jend)
                jend = iend;
    
    
    tjc's avatar
    tjc committed
              final Integer coords[] = new Integer[2];
    
              coords[0] = new Integer(istart);
              coords[1] = new Integer(jend);
              union.add(coords);
            }
          }
        }
    
        return union;
      }
    
      /**
      *
      * Create features from Vector of coordinates.
      * @param diffs Vector of coordinates to create feature from.
      * @param frame The JFrame that owns this JMenu.
      *
      */
    
      private void createFeatures(Vector diffs, JFrame frame, String name) 
    
      {
        Enumeration eDiffs = diffs.elements();
        while(eDiffs.hasMoreElements())
        {
          Integer coords[] = (Integer[])eDiffs.nextElement();
          int start = coords[0].intValue();
          int end   = coords[1].intValue();
    //    System.out.println(start+" "+end);
             
          final Entry default_entry = entry_group.getDefaultEntry();
          if(default_entry == null) 
          {
            new MessageDialog(frame, "There is no default entry");
            return;
          }
    
          Location loc = null;
          Feature temp_feature;
          try 
          {
            loc = new Location(start+".."+end);
    
            Key misc_feature = new Key("misc_feature");
            temp_feature = default_entry.createFeature(misc_feature, loc);
            Qualifier note = new Qualifier("note",
                                           "Automatically generated region of difference with "+
                                           name);
    
            temp_feature.setQualifier(note);
    
          } 
          catch(EntryInformationException e) 
          {
            // use the default key instead
            final Key default_key =
              default_entry.getEntryInformation().getDefaultKey();
    
            try
            {
              temp_feature =
                  default_entry.createFeature(default_key, loc);
            }
            catch(EntryInformationException einfo)
            {
              throw new Error("internal error - unexpected exception: " + einfo);
            }
            catch(ReadOnlyException eRead)
            {
              new MessageDialog(frame, "feature not created: " +
                              "the default entry is read only");
            }
            catch(OutOfRangeException eout)
            {
              throw new Error("internal error - unexpected exception: " + eout);
            }
    
          }
          catch(ReadOnlyException e) 
          {
            new MessageDialog(frame, "feature not created: " +
                            "the default entry is read only");
          } 
          catch(OutOfRangeException e) 
          {
            throw new Error("internal error - unexpected exception: " + e);
          }
          catch(LocationParseException  lpe)
          {
            throw new Error("internal error - unexpected exception: " + lpe);
          }
        }
      }
    
    
    tjc's avatar
    tjc committed
      /**
       *  Create a new AddMenu object.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param entry_group The EntryGroup object where new features/entries will
       *    be added.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
       **/
      public AddMenu (final JFrame frame,
                      final Selection selection,
                      final EntryGroup entry_group,
                      final GotoEventSource goto_event_source,
                      final BasePlotGroup base_plot_group) {
        this (frame, selection, entry_group,
              goto_event_source, base_plot_group, "Create");
      }
    
      /**
       *  Create a new feature in the default Entry of the entry group.  See
       *  EntryGroup.createFeature () for details.
       **/
      private void makeNewFeature () {
        if (entry_group.size () > 0) {
          if (entry_group.getDefaultEntry () == null) {
            new MessageDialog (getParentFrame (), "There is no default entry");
          } else {
    
            try {
              entry_group.getActionController ().startAction ();
    
              final Feature new_feature = entry_group.createFeature ();
    
    
    tjc's avatar
    tjc committed
              
              final JFrame edit_frame = new JFrame("Artemis Feature Edit: " + 
                  new_feature.getIDString() +
                  (new_feature.isReadOnly() ?
                      "  -  (read only)" :
                      ""));
              
              final FeatureEdit feature_edit = new FeatureEdit(new_feature, entry_group,
                  getSelection(), getGotoEventSource(), edit_frame);
              
              edit_frame.addWindowListener(new WindowAdapter() 
              {
                public void windowClosing(WindowEvent event) 
                {
                  feature_edit.stopListening();
                  edit_frame.dispose();
                }
              });
              
              edit_frame.getContentPane().add(feature_edit);
              edit_frame.pack();
    
    
    tjc's avatar
    tjc committed
              //final Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
              //edit_frame.setLocation(new Point((screen.width - edit_frame.getSize().width)/2,
              //                            (screen.height - edit_frame.getSize().height)/2));
              Utilities.centreFrame(edit_frame);
              
    
    tjc's avatar
    tjc committed
              final ActionListener cancel_listener =
                new ActionListener () {
                  public void actionPerformed (ActionEvent e) {
                    try {
                      new_feature.removeFromEntry ();
                    } catch (ReadOnlyException exception) {
                      throw new Error ("internal error - unexpected exception: " +
                                       exception);
                    }
                  }
                };
    
              feature_edit.addCancelActionListener (cancel_listener);
    
              feature_edit.addApplyActionListener (new ActionListener () {
                public void actionPerformed (ActionEvent e) {
                  // after apply is pressed cancel should not remove the new
                  // feature
                  feature_edit.removeCancelActionListener (cancel_listener);
                }
              });
    
    
    tjc's avatar
    tjc committed
              edit_frame.setVisible(true);
    
    tjc's avatar
    tjc committed
            } catch (ReadOnlyException e) {
              new MessageDialog (getParentFrame (), "feature not created: " +
                                 "the default entry is read only");
            } finally {
              entry_group.getActionController ().endAction ();
            }
          }
        } else {
          new MessageDialog (getParentFrame (),
                             "Cannot make a feature without an existing entry");
        }
      }
    
      /**
       *  Create a new Entry in the first Entry of the entry group.
       **/
      private void makeNewEntry () {
        entry_group.createEntry ();
      }
    
      /**
       *  Create a new Feature in entry_group from the selected range of bases and
       *  then display a FeatureEdit component for the new Feature.
       *  @param frame The JFrame to use for MessageDialog components.
       *  @param selection The Selection containing the sequence to create the
       *    feature from.
       *  @param entry_group The EntryGroup to create the feature in.
       *  @param goto_event_source Needed to create a FeatureEdit component.
       **/
      static void createFeatureFromBaseRange (final JFrame frame,
                                              final Selection selection,
                                              final EntryGroup entry_group,
                                              final GotoEventSource
                                                goto_event_source) {
        try {
          entry_group.getActionController ().startAction ();
    
          if (!checkForSelectionRange (frame, selection)) {
            return;
          }
    
          final MarkerRange range = selection.getMarkerRange ();
          final Entry default_entry = entry_group.getDefaultEntry ();
    
          if (default_entry == null) {
            new MessageDialog (frame, "There is no default entry");
            return;
          }
    
          try {
            final Location new_location = range.createLocation ();
    
            /*final*/ Feature temp_feature;
    
            QualifierVector qualifiers = null;
    
    tjc's avatar
    tjc committed
            final boolean isDatabaseEntry = GeneUtils.isDatabaseEntry(entry_group);
    
    tjc's avatar
    tjc committed
            if(isDatabaseEntry)
    
    tjc's avatar
    tjc committed
              String uniquename = GeneUtils.promptForUniquename(entry_group, 
    
                                         range.isForwardMarker(), range.getRawRange());
    
              Qualifier qualifier = new Qualifier("ID", uniquename);
              qualifiers = new QualifierVector();
              qualifiers.add(qualifier);
            }
            
            try 
            {
    
    tjc's avatar
    tjc committed
              final Key key;
              if(isDatabaseEntry)
    
    tjc's avatar
    tjc committed
                key = new Key("region");
    
    tjc's avatar
    tjc committed
              else
                key = Key.CDS;
              
    
              if(qualifiers == null)
    
    tjc's avatar
    tjc committed
                temp_feature = default_entry.createFeature (key, new_location);
    
    tjc's avatar
    tjc committed
                temp_feature = default_entry.createFeature (key, new_location, qualifiers);
              
    
    tjc's avatar
    tjc committed
            /*if(isDatabaseEntry)
    
    tjc's avatar
    tjc committed
              {
                final ChadoCanonicalGene chado_gene = new ChadoCanonicalGene();
                chado_gene.setGene(temp_feature.getEmblFeature());
                ((uk.ac.sanger.artemis.io.GFFStreamFeature)
                  (temp_feature.getEmblFeature())).setChadoGene(chado_gene);
    
    tjc's avatar
    tjc committed
              }*/
    
            }
            catch (EntryInformationException e) 
            {
    
    tjc's avatar
    tjc committed
              // use the default key instead
    
              final Key default_key =
                default_entry.getEntryInformation ().getDefaultKey ();
    
    
              try 
              {
                if(qualifiers == null)
                  temp_feature =
                    default_entry.createFeature (default_key, new_location);
                else
                  temp_feature =
                    default_entry.createFeature (default_key, new_location, qualifiers);
              } 
              catch (EntryInformationException ex) 
              {
    
    tjc's avatar
    tjc committed
                throw new Error ("internal error - unexpected exception: " + ex);
              }
            }
    
            final Feature new_feature = temp_feature;
    
            selection.setMarkerRange (null);
            selection.set (new_feature);
    
    tjc's avatar
    tjc committed
            
    
    tjc's avatar
    tjc committed
            final ActionListener cancel_listener = new ActionListener() 
    
    tjc's avatar
    tjc committed
            {
    
    tjc's avatar
    tjc committed
              public void actionPerformed(ActionEvent e)
    
    tjc's avatar
    tjc committed
              {
    
    tjc's avatar
    tjc committed
                try 
                {
                  new_feature.removeFromEntry ();
                  selection.setMarkerRange(range);
                }
                catch (ReadOnlyException exception) 
                {
                  throw new Error("internal error - unexpected exception: " +
                                  exception);
    
    tjc's avatar
    tjc committed
                }
              }
    
    tjc's avatar
    tjc committed
            };
              
            EditMenu.editSelectedFeatures(entry_group, selection, goto_event_source,
                new_feature, cancel_listener, null);
    
    tjc's avatar
    tjc committed
    
          } catch (ReadOnlyException e) {
            new MessageDialog (frame, "feature not created: " +
                               "the default entry is read only");
          } catch (OutOfRangeException e) {
            throw new Error ("internal error - unexpected exception: " + e);
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Create a new intron between each pair of exons in the selected CDS
       *  features.  The introns are created in the Entry that contains the CDSs.
       *  @param frame The Frame to use for MessageDialog components.
       *  @param selection The Selection containing the CDS features to create the
       *    introns for.
       *  @param entry_group The EntryGroup to create the features in.
       **/
      static void createIntronFeatures (final JFrame frame,
                                        final Selection selection,
                                        final EntryGroup entry_group) {
        try {
          entry_group.getActionController ().startAction ();
    
          if (!checkForSelectionFeatures (frame, selection)) {
            return;
          }
    
          final FeatureVector selected_features = selection.getAllFeatures ();
    
          for (int feature_index = 0 ;
               feature_index < selected_features.size () ;
               ++feature_index) {
    
            final Feature selection_feature =
              selected_features.elementAt (feature_index);
    
    
            if (!(selection_feature.isProteinFeature () ||
                  selection_feature.getKey().equals("5'UTR") ||
                  selection_feature.getKey().equals("3'UTR"))) {
    
    tjc's avatar
    tjc committed
              continue;
            }
    
            final Location cds_location = selection_feature.getLocation ();
    
            final RangeVector cds_ranges = cds_location.getRanges ();
    
            if (cds_ranges.size () < 2) {
              continue;
            }
    
            if (cds_location.isComplement ()) {
              cds_ranges.reverse ();
            }
    
    
    tjc's avatar
    tjc committed
            for (int range_index = 0 ;
                 range_index < cds_ranges.size () - 1 ;
                 ++range_index) {
              final int end_of_range_1 =
    
    tjc's avatar
    tjc committed
                ((Range)cds_ranges.elementAt(range_index)).getEnd ();
    
    tjc's avatar
    tjc committed
              final int start_of_range_2 =
    
    tjc's avatar
    tjc committed
                ((Range)cds_ranges.elementAt(range_index + 1)).getStart ();
    
    tjc's avatar
    tjc committed
    
              if (end_of_range_1 > start_of_range_2) {
                // ignore - the exons overlap so there is no room for an intron
                continue;
              }
    
    
              Range new_range = null;
    
    tjc's avatar
    tjc committed
    
              try {
                new_range = new Range (end_of_range_1 + 1,
                                       start_of_range_2 - 1);
              } catch (OutOfRangeException e) {
    
                Object[] options = { "CANCEL", "IGNORE", "IGNORE ALL"};
    
                if(select != 2)
                {
                  select = JOptionPane.showOptionDialog(null,
                              "Found overlapping CDS\n"+e,
                              "Out of Range",
                               JOptionPane.YES_NO_CANCEL_OPTION,
                               JOptionPane.WARNING_MESSAGE,
                               null,
                               options,
                               options[0]);
                  if(select == 0)
                    throw new Error ("internal error - unexpected exception: " + e);
                 
                  continue;
                }
    
    tjc's avatar
    tjc committed
              }
    
              final RangeVector intron_ranges = new RangeVector ();
    
              intron_ranges.add (new_range);
    
              final Key intron_key = new Key ("intron");
              final Location intron_location =
                new Location (intron_ranges, cds_location.isComplement ());
              final QualifierVector qualifiers = new QualifierVector ();
    
    
              try {
                StringVector sysNames = Options.getOptions().getSystematicQualifierNames();
                for(int i=0; i<sysNames.size(); i++) {
                  Qualifier qual = selection_feature.getQualifierByName((String) sysNames.get(i));
                  if(qual != null && qual.getValues() != null && qual.getValues().size() > 0) {
                    qualifiers.addQualifierValues(qual);
                    break;
                  }
                }
              } catch (InvalidRelationException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              }
              
    
    tjc's avatar
    tjc committed
              try {
                selection_feature.getEntry ().createFeature (intron_key,
                                                             intron_location,
                                                             qualifiers);
              } catch (ReadOnlyException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              } catch (EntryInformationException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              } catch (OutOfRangeException e) {
    
                Object[] options = { "CANCEL", "IGNORE", "IGNORE ALL"};
    
                if(select != 2)
                {
                  select = JOptionPane.showOptionDialog(null, 
                              "Found overlapping CDS\n"+e,
                              "Out of Range",
                               JOptionPane.YES_NO_CANCEL_OPTION,
                               JOptionPane.WARNING_MESSAGE,
                               null,
                               options,
                               options[0]);
                  if(select == 0)
                    throw new Error ("internal error - unexpected exception: " + e);
                }
    
    tjc's avatar
    tjc committed
              }
            }
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
    
      
      /**
       *  Create intergenic regions between CDS.
       *  @param frame The Frame to use for MessageDialog components.
       *  @param entry_group The EntryGroup to create the features in.
       **/
      static void createIntergenicFeatures (final JFrame frame,
                                        final EntryGroup entry_group) 
      {
    
          entry_group.getActionController ().startAction ();
    
    
          final FeaturePredicate predicate;
    
    tjc's avatar
    tjc committed
          
          if(GeneUtils.isDatabaseEntry(entry_group))
            predicate = new FeatureKeyPredicate(new Key("gene"));
          else
    
          {
            final FeaturePredicateVector temp_predicates =
              new FeaturePredicateVector();
            
            temp_predicates.add(new FeatureKeyPredicate(Key.CDS));
            temp_predicates.add(new FeatureKeyPredicate(new Key("tRNA")));
            
            predicate =
              new FeaturePredicateConjunction(temp_predicates,
                                              FeaturePredicateConjunction.OR);
          }
          
          FeatureVector cdsFeatures = new FeatureVector ();
    
          final FeatureEnumeration feature_enum = entry_group.features ();
          while (feature_enum.hasMoreFeatures ()) 
          {
            final Feature current_feature = feature_enum.nextFeature ();
            if(predicate.testPredicate (current_feature)) 
              cdsFeatures.add (current_feature);
          }
    
    
          cdsFeatures = cdsFeatures.sort(feature_comparator);
    
          int prevEnd = 0;
    
          Entry newEntry = null;
    
          boolean prevForward = true;
    
          // search for intergenic regions
    
          for(int i=0; i < cdsFeatures.size (); i++)
    
            final Feature this_feature = cdsFeatures.elementAt(i);
            final Location cds_location = this_feature.getLocation();
            final Range r = cds_location.getTotalRange();
            
    
            int currentStart = r.getStart();
            
            if(i==0 && r.getStart()==1)
            {
              prevEnd = r.getEnd();
    
              prevForward = this_feature.isForwardFeature();
    
              // check for overlapping CDS
    
              if(i<cdsFeatures.size()-1)
    
            	  int next = i+1; 	
    
                while(getTotalRange((Feature)cdsFeatures.elementAt(next)).getStart() <= prevEnd+1)
    
                  Feature f = (Feature)cdsFeatures.elementAt(next);
    
                  
                  if(prevEnd < getTotalRange(f).getEnd())
                  {
                    prevEnd = getTotalRange(f).getEnd();
                    prevForward = f.isForwardFeature();
                  }
                  
    
              continue;
            }
            
            try 
            {
              Range new_range = new Range(prevEnd + 1,
                                          currentStart - 1);
              Location location = new Location(new_range);
    
    tjc's avatar
    tjc committed
              final Key key;
              
              if(GeneUtils.isDatabaseEntry(entry_group))
                key = new Key ("region");            
              else
                key = new Key ("misc_feature");
    
              
              
              // intergenic regions (IGR) - flanking CDS 4 possible:
              // IGR-F (forward):  cds> IGR cds>
              // IGR-R (reverse): <cds IGR <cds
              // IGR-B (both): <cds IGR cds>
              // IGR-X: cds> IGR <cds
              String note;
              
              if(this_feature.isForwardFeature())
              {
                if(prevForward)
                  note = "IGR-F";
                else
                  note = "IGR-B";
              }
              else
              {
                if(prevForward)
                  note = "IGR-X";
                else
                  note = "IGR-R";
              }
    
              final QualifierVector qualifiers = new QualifierVector ();
    
              final Qualifier qualifier = new Qualifier("note", note);
              qualifiers.add(qualifier);
    
              
              if(newEntry == null)
                newEntry = entry_group.createEntry("intergenic");
              
              newEntry.createFeature(key, location, qualifiers);
    
              prevEnd = r.getEnd();
    
              prevForward = this_feature.isForwardFeature();
    
              // check for overlapping CDS
    
              if(i<cdsFeatures.size()-1)
    
            	  int next = i+1;
    
                while( next < cdsFeatures.size() &&
                      getTotalRange((Feature)cdsFeatures.elementAt(next)).getStart() <= prevEnd+1)
    
                  Feature f = (Feature)cdsFeatures.elementAt(next);
    
                  
                  if(prevEnd < getTotalRange(f).getEnd())
                  {
                    prevEnd = getTotalRange(f).getEnd();