Skip to content
Snippets Groups Projects
SelectMenu.java 31.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
    /* SelectMenu.java
     *
     * created: Thu Jan 14 1999
     *
     * This file is part of Artemis
     *
     * Copyright (C) 1998,1999,2000  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/SelectMenu.java,v 1.11 2007-10-01 14:54:45 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    package uk.ac.sanger.artemis.components;
    
    import uk.ac.sanger.artemis.*;
    import uk.ac.sanger.artemis.sequence.*;
    
    
    import uk.ac.sanger.artemis.util.DatabaseDocument;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.util.OutOfRangeException;
    import uk.ac.sanger.artemis.util.StringVector;
    
    import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
    
    tjc's avatar
    tjc committed
    import uk.ac.sanger.artemis.io.Range;
    import uk.ac.sanger.artemis.io.Key;
    import uk.ac.sanger.artemis.io.KeyVector;
    import uk.ac.sanger.artemis.io.Qualifier;
    import uk.ac.sanger.artemis.io.InvalidRelationException;
    import uk.ac.sanger.artemis.io.EntryInformation;
    
    import uk.ac.sanger.artemis.io.Location;
    
    tjc's avatar
    tjc committed
    
    
    
    import java.awt.Cursor;
    import java.awt.Toolkit;
    
    tjc's avatar
    tjc committed
    import java.awt.event.*;
    
    import java.util.Vector;
    import java.util.Enumeration;
    
    
    import javax.swing.JCheckBox;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JMenuItem;
    import javax.swing.JOptionPane;
    import javax.swing.KeyStroke;
    
    
    tjc's avatar
    tjc committed
    
    /**
     *  This menu has contains items such a "Select all", "Select none" and
     *  "Select by key".
     *
     *  @author Kim Rutherford
    
     *  @version $Id: SelectMenu.java,v 1.11 2007-10-01 14:54:45 tjc Exp $
    
    tjc's avatar
    tjc committed
     **/
    
    
    public class SelectMenu extends SelectionMenu 
    {
    
    
      private static final long serialVersionUID = 1L;
    
    
      /**
       *  The EntryGroup object that was passed to the constructor.
       **/
      private EntryGroup entry_group;
    
      /**
       *  The GotoEventSource object that was passed to the constructor.
       **/
      private GotoEventSource goto_event_source;
    
      private JMenuItem selector_item = null;
      private JMenuItem all_item = null;
      private JMenuItem all_bases_item = null;
      private JMenuItem none_item = null;
      private JMenuItem selection_toggle_item = null;
      private JMenuItem select_same_type_item = null;
      private JMenuItem select_matching_qualifiers_item = null;
      private JMenuItem select_features_in_range_item = null;
      private JMenuItem select_base_range_item = null;
      private JMenuItem select_aa_range_in_feature_item = null;
      private JMenuItem select_orf_item = null;
      private JMenuItem select_by_key_item = null;
      private JMenuItem select_non_pseudo_cds_item = null;
      private JMenuItem select_all_cds_item = null;
    
      /**
       *  The shortcut for Select All
       **/
      final static KeyStroke SELECT_ALL_KEY =
    
        KeyStroke.getKeyStroke(KeyEvent.VK_A, 
                               Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); //InputEvent.CTRL_MASK);
    
    
      /**
       *  The shortcut for Select None
       **/
      final static KeyStroke SELECT_NONE_KEY =
    
        KeyStroke.getKeyStroke (KeyEvent.VK_N, 
                               Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); //InputEvent.CTRL_MASK);
    
    
    
      /**
       *  Warn if the user tries to select more than this number of features.
       **/
      final private int MAX_FEATURE_TO_SELECT_COUNT = 10000;
    
    
    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
      /**
       *  Create a new SelectMenu object and all it's menu items.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param entry_group The EntryGroup object where features and exons are
       *    selected from.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
       *  @param menu_name The name of the new menu.
       **/
    
      public SelectMenu(final JFrame frame,
                        final Selection selection,
                        final GotoEventSource goto_event_source,
                        final EntryGroup entry_group,
                        final BasePlotGroup base_plot_group,
                        final String menu_name)
     {
       this(frame,selection,goto_event_source,entry_group,
            base_plot_group,null,null,menu_name);
     }
    
      /**
       *  Create a new SelectMenu object and all it's menu items.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param entry_group The EntryGroup object where features and exons are
       *    selected from.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
       *  @param menu_name The name of the new menu.
       **/
      public SelectMenu(final JFrame frame,
                        final Selection selection,
                        final GotoEventSource goto_event_source,
                        final EntryGroup entry_group,
                        final BasePlotGroup base_plot_group,
                        final AlignmentViewer alignQueryViewer,  
                        final AlignmentViewer alignSubjectViewer,
                        final String menu_name) 
     {
        super(frame, menu_name, selection);
    
    tjc's avatar
    tjc committed
    
        this.entry_group = entry_group;
        this.goto_event_source = goto_event_source;
    
    
        selector_item = new JMenuItem("Feature Selector ...");
        selector_item.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent event) 
          {
            new Selector(selection, goto_event_source, getEntryGroup(),
                         base_plot_group);
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(selector_item);
    
    tjc's avatar
    tjc committed
    
    
        addSeparator();
    
    tjc's avatar
    tjc committed
    
    
        all_item = new JMenuItem("All");
        all_item.setAccelerator(SELECT_ALL_KEY);
        all_item.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent event) 
          {
    
    tjc's avatar
    tjc committed
            frame.setCursor(cbusy);
    
            selectAll();
    
    tjc's avatar
    tjc committed
            frame.setCursor(cdone);
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(all_item);
    
    tjc's avatar
    tjc committed
    
    
        all_bases_item = new JMenuItem("All Bases");
        all_bases_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
    
    tjc's avatar
    tjc committed
            frame.setCursor(cbusy);
    
            selectAllBases();
    
    tjc's avatar
    tjc committed
            frame.setCursor(cdone);
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(all_bases_item);
    
    
        if(alignQueryViewer != null || alignSubjectViewer != null)
        {
          JMenuItem all_diffs = new JMenuItem("All Features in Non-matching Regions");
          all_diffs.addActionListener(new ActionListener() 
          {
            public void actionPerformed(ActionEvent event) 
            {
    
              final JCheckBox cbox_strict = new JCheckBox("Strictly no overlapping regions",true);
    
              int n = JOptionPane.showConfirmDialog(null, cbox_strict,
                                "Selecting Features in Non-matching Regions",
                                JOptionPane.OK_CANCEL_OPTION,
                                JOptionPane.QUESTION_MESSAGE);
    
              if(n == JOptionPane.CANCEL_OPTION)
                return;
    
    
    tjc's avatar
    tjc committed
              frame.setCursor(cbusy);
    
              Vector diffs = null;
              if(alignQueryViewer == null || alignSubjectViewer == null)
              {
                if(alignQueryViewer != null)
                  diffs = alignQueryViewer.getDifferenceCoords(false);
                else
    
    tjc's avatar
    tjc committed
                  diffs = alignSubjectViewer.getDifferenceCoords(true);
    
              }
              else
              {
                final Vector diffs1 = alignQueryViewer.getDifferenceCoords(false);
                final Vector diffs2 = alignSubjectViewer.getDifferenceCoords(false);
                diffs = AddMenu.union(diffs1,diffs2);
              }
    
              if(diffs != null)
    
                selectAllFeatures(diffs,cbox_strict.isSelected());
    
    tjc's avatar
    tjc committed
              frame.setCursor(cdone);
    
    tjc's avatar
    tjc committed
    
    
        none_item = new JMenuItem("None");
        none_item.setAccelerator(SELECT_NONE_KEY);
        none_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            clearSelection();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(none_item);
    
    tjc's avatar
    tjc committed
    
    
        select_by_key_item = new JMenuItem("By Key");
        select_by_key_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectByKeyPopup();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_by_key_item);
    
    tjc's avatar
    tjc committed
    
        select_non_pseudo_cds_item =
    
          new JMenuItem("CDS Features without /pseudo");
        select_non_pseudo_cds_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event)
          {
    
    tjc's avatar
    tjc committed
            // select all CDS features that do not have the /pseudo qualifier
            final FeatureKeyQualifierPredicate predicate =
    
              new FeatureKeyQualifierPredicate(Key.CDS, "pseudo", false);
    
    tjc's avatar
    tjc committed
    
    
            clearSelection();
    
    tjc's avatar
    tjc committed
    
    
            selectFeaturesByPredicate(predicate);
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_non_pseudo_cds_item);
    
    tjc's avatar
    tjc committed
    
    
        
        final boolean isDatabaseGroup = GeneUtils.isDatabaseEntry( getEntryGroup() );
        
        if(isDatabaseGroup)
        {
          select_non_pseudo_cds_item.setEnabled(false);
          select_all_cds_item = new JMenuItem("All Exon Model Features");
        }
        else
          select_all_cds_item = new JMenuItem("All CDS Features");
    
        select_all_cds_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
    
            final FeatureKeyPredicate predicate;
            if(isDatabaseGroup)
              predicate = new FeatureKeyPredicate(new Key(DatabaseDocument.EXONMODEL));
            else
              predicate = new FeatureKeyPredicate(Key.CDS);
    
    tjc's avatar
    tjc committed
    
    
            clearSelection();
    
    tjc's avatar
    tjc committed
    
    
            selectFeaturesByPredicate(predicate);
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_all_cds_item);
    
    tjc's avatar
    tjc committed
    
    
        select_same_type_item = new JMenuItem("Same Key");
        select_same_type_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectSameKey();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_same_type_item);
    
    tjc's avatar
    tjc committed
    
        select_matching_qualifiers_item =
    
          new JMenuItem("Features Matching Qualifier");
        select_matching_qualifiers_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectMatchingQualifiers();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_matching_qualifiers_item);
    
    tjc's avatar
    tjc committed
    
    
        select_orf_item = new JMenuItem("Open Reading Frame");
        select_orf_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectOrf();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_orf_item);
    
    tjc's avatar
    tjc committed
    
        select_features_in_range_item =
    
          new JMenuItem("Features Overlapping Selection");
        select_features_in_range_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectOverlappingFeatures();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_features_in_range_item);
    
    tjc's avatar
    tjc committed
    
    
        select_base_range_item = new JMenuItem("Base Range ...");
        select_base_range_item.addActionListener(new ActionListener()
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectBaseRange();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_base_range_item);
    
    tjc's avatar
    tjc committed
    
    
        select_aa_range_in_feature_item = new JMenuItem("Feature AA Range ...");
        select_aa_range_in_feature_item.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent event) 
          {
            selectFeatureAARange();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(select_aa_range_in_feature_item);
    
    tjc's avatar
    tjc committed
    
    
        addSeparator();
    
    tjc's avatar
    tjc committed
    
    
        selection_toggle_item = new JMenuItem("Toggle Selection");
        selection_toggle_item.addActionListener(new ActionListener() 
        {
          public void actionPerformed(ActionEvent event) 
          {
            toggleSelection();
    
    tjc's avatar
    tjc committed
          }
        });
    
    
        add(selection_toggle_item);
    
    tjc's avatar
    tjc committed
      }
    
    
      /**
       *  Create a new SelectMenu object and all it's menu items.
       *  @param frame The JFrame that owns this JMenu.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param goto_event_source The object the we will call makeBaseVisible ()
       *    on.
       *  @param entry_group The EntryGroup object where features and exons are
       *    selected from.
       *  @param base_plot_group The BasePlotGroup associated with this JMenu -
       *    needed to call getCodonUsageAlgorithm()
       **/
    
      public SelectMenu(final JFrame frame,
                        final Selection selection,
                        final GotoEventSource goto_event_source,
                        final EntryGroup entry_group,
                        final BasePlotGroup base_plot_group) 
      {
    
    tjc's avatar
    tjc committed
        this (frame, selection, goto_event_source, entry_group,
              base_plot_group, "Select");
      }
    
    
      /**
       *  Select all the features in the active entries.  If there are more than
       *  1000 features the user is asked for confirmation.
       **/
    
      private void selectAll() 
      {
        if(getEntryGroup().getAllFeaturesCount() >
           MAX_FEATURE_TO_SELECT_COUNT) 
        {
    
    tjc's avatar
    tjc committed
          final YesNoDialog dialog =
    
            new YesNoDialog(getParentFrame(),
                            "Are you sure you want to select " +
                             getEntryGroup().getAllFeaturesCount() +
                            " features?");
    
    tjc's avatar
    tjc committed
    
    
          if(!dialog.getResult ()) 
    
    tjc's avatar
    tjc committed
            return;
        }
    
    
        final FeatureVector all_features = getEntryGroup().getAllFeatures();
    
    tjc's avatar
    tjc committed
    
    
        if(getEntryGroup() instanceof SimpleEntryGroup) 
        {
    
    tjc's avatar
    tjc committed
          // special case for speed
    
          getSelection().set(all_features);
        } 
        else 
        {
          clearSelection();
          getSelection().add(all_features);
    
    tjc's avatar
    tjc committed
        }
      }
    
      /**
       *  Select all the bases.
       **/
    
      private void selectAllBases()
      {
        try 
        {
          final Strand strand = getEntryGroup().getBases().getForwardStrand();
    
    tjc's avatar
    tjc committed
    
          final MarkerRange new_range =
    
            strand.makeMarkerRangeFromPositions(1, strand.getSequenceLength());
    
    tjc's avatar
    tjc committed
    
    
          getSelection().setMarkerRange(new_range);
        }
        catch (OutOfRangeException e) 
        {
    
    tjc's avatar
    tjc committed
          throw new Error ("internal error - unexpected exception: " + e);
        }
      }
    
    
    tjc's avatar
    tjc committed
    
      /**
      *
      * Select all features in a given collection of regions.
    
      * @param regions   Vector of coordinates of non-matching region.
      * @param isStrict  true if not allowing any overlap with matching region.
    
    tjc's avatar
    tjc committed
      *
      */
    
      private void selectAllFeatures(final Vector regions, final boolean isStrict)
    
      {
        
        final FeaturePredicate predicate = new FeaturePredicate()
        {
          public boolean testPredicate(final Feature feature)
          {
            final Location loc = feature.getLocation();
    
    tjc's avatar
    tjc committed
            Key key = feature.getKey();
            if(key.equals("source"))
              return false;
    
    
            final int feat_start = loc.getFirstBase();
            final int feat_end   = loc.getLastBase();
    
    tjc's avatar
    tjc committed
    //      final int feat_len   = feature.getBaseCount();
    
    tjc's avatar
    tjc committed
            int diff_start;
            int diff_end;
            Integer coords[];
    
    
            Enumeration eDiffs = regions.elements();
            while(eDiffs.hasMoreElements())
            {
    
    tjc's avatar
    tjc committed
              coords = (Integer[])eDiffs.nextElement();
              diff_start = coords[0].intValue();
              diff_end   = coords[1].intValue();
    
    tjc's avatar
    tjc committed
    
    
              if( isStrict && feat_start >= diff_start && feat_start <= diff_end &&
                               feat_end >= diff_start   && feat_end <= diff_end )
                return true;
              else if( !isStrict && 
                       ((feat_start >= diff_start && feat_start <= diff_end)  ||
                        (feat_end >= diff_start   && feat_end <= diff_end) ||
                        (diff_start >= feat_start && diff_start <= feat_end) ||
                        (diff_end >= feat_start   && diff_end <= feat_end )) )
    
                return true;
    
    tjc's avatar
    tjc committed
              else if(diff_start > feat_end)
                return false;
    
            }
    
            return false;
          }
        };
    
        selectFeaturesByPredicate(predicate);
      }
    
    
    tjc's avatar
    tjc committed
      /**
       *  Remove the all Features and FeatureSegments in the EntryGroup from the
       *  Selection.  If the current EntryGroup is a SimpleEntryGroup then this
       *  method just calls getSelection ().clear ();
       **/
    
      private void clearSelection () 
      {
    
    tjc's avatar
    tjc committed
        if (getEntryGroup () instanceof SimpleEntryGroup) {
          // special case for speed
          getSelection ().clear ();
        } else {
          getSelection ().setMarkerRange (null);
    
          final FeatureEnumeration test_enumerator = getEntryGroup ().features ();
    
          while (test_enumerator.hasMoreFeatures ()) {
            final Feature this_feature = test_enumerator.nextFeature ();
    
            getSelection ().remove (this_feature);
            getSelection ().removeSegmentsOf (this_feature);
          }
        }
      }
    
      /**
       *  Invert the selection - after calling this method the selection will
       *  contain only those features that were not in the selection before the
       *  call.
       **/
      private void toggleSelection () {
        final FeatureVector selected_features = getSelection ().getAllFeatures ();
    
        final FeatureVector all_features = getEntryGroup ().getAllFeatures ();
    
        final FeatureVector new_selection = new FeatureVector ();
    
        for (int i = 0 ; i < all_features.size () ; ++i) {
          final Feature this_feature = all_features.elementAt (i);
    
          if (!selected_features.contains (this_feature)) {
            new_selection.add (this_feature);
          }
        }
    
        clearSelection ();
    
        getSelection ().add (new_selection);
      }
    
    
      /**
       *  Popup a TextRequester component and then select all the features that
       *  have the same key as the user types.
       **/
      private void selectByKeyPopup () {
        final KeyChooser key_chooser;
    
        final EntryInformation default_entry_information =
          Options.getArtemisEntryInformation ();
    
        key_chooser = new KeyChooser (default_entry_information,
                                      new Key ("misc_feature"));
    
        key_chooser.getKeyChoice ().addItemListener (new ItemListener () {
          public void itemStateChanged (ItemEvent _) {
            selectByKey (key_chooser.getKeyChoice ().getSelectedItem ());
            key_chooser.setVisible (false);
            key_chooser.dispose ();
          }
        });
    
        key_chooser.getOKButton ().addActionListener (new ActionListener () {
          public void actionPerformed (ActionEvent _) {
            selectByKey (key_chooser.getKeyChoice ().getSelectedItem ());
            key_chooser.setVisible (false);
            key_chooser.dispose ();
          }
        });
    
        key_chooser.setVisible (true);
      }
    
      /**
       *  Select all the features that have the given key.
       **/
      private void selectByKey (final Key key) {
        final FeaturePredicate predicate = new FeatureKeyPredicate (key);
    
        selectFeaturesByPredicate (predicate);
      }
    
      /**
       *  Select all the features that have the given key and contains a qualifier
       *  with the given name and value.
       *  If key is null select any feature with the contains a qualifier with the
       *  given name and value.
       **/
      private void selectByQualifier (final Key key,
                                      final String name, final String value) {
        final FeaturePredicate predicate =
          new FeatureKeyQualifierPredicate (key, name, value);
    
        selectFeaturesByPredicate (predicate);
      }
    
      /**
       *  Select all the features that have the same key as the currently selected
       *  features.
       **/
      private void selectSameKey () {
        if (! checkForSelectionFeatures ()) {
          return;
        }
    
        final KeyVector seen_keys = new KeyVector ();
    
        final FeatureVector selected_features = getSelection ().getAllFeatures ();
    
        for (int i = 0 ; i < selected_features.size () ; ++i) {
          final Feature current_feature = selected_features.elementAt (i);
    
          if (!seen_keys.contains (current_feature.getKey ())) {
            seen_keys.add (current_feature.getKey ());
          }
        }
    
        clearSelection ();
    
        for (int i = 0 ; i < seen_keys.size () ; ++i) {
    
          selectByKey ((Key)seen_keys.get(i));
    
    tjc's avatar
    tjc committed
        }
      }
    
      /**
       *  Ask the user for a qualifier name, list all of the qualifier with that
       *  name in the currently selected feature then select all features that
       *  have that name and qualifier.
       **/
      private void selectMatchingQualifiers () {
        if (!checkForSelectionFeatures (getParentFrame (), getSelection ())) {
          return;
        }
    
        final FeatureVector selected_features = getSelection ().getAllFeatures ();
    
        if (selected_features.size () > 1) {
          new MessageDialog (getParentFrame (), "select only one feature");
          return;
        }
    
        final Feature selected_feature = selected_features.elementAt (0);
    
        final StringVector qualifier_names =
          Feature.getAllQualifierNames (selected_features);
    
        if (qualifier_names.size () == 0) {
          new MessageDialog (getParentFrame (), "feature has no qualifiers");
          return;
        }
    
        final ChoiceFrame name_choice_frame =
          new ChoiceFrame ("Select a qualifier name ...", qualifier_names);
    
        final JComboBox name_choice = name_choice_frame.getChoice ();
    
        class SelectListener implements ActionListener, ItemListener {
          public void doStuff () {
            selectMatchingQualifiersHelper (selected_feature,
                                            (String) name_choice.getSelectedItem ());
            name_choice_frame.setVisible (false);
            name_choice_frame.dispose ();
          }
    
          public void itemStateChanged (ItemEvent _) {
            doStuff ();
            // need to remove() because itemStateChanged() is called twice on the
            // Tru64 1.4.1 JVM
            name_choice.removeItemListener (this);
          }
    
          public void actionPerformed (ActionEvent _) {
            doStuff ();
            name_choice_frame.getOKButton ().removeActionListener (this);
          }
        };
    
        final SelectListener listener = new SelectListener ();
    
        name_choice.addItemListener (listener);
        name_choice_frame.getOKButton ().addActionListener (listener);
    
        name_choice_frame.setVisible (true);
      }
    
      /**
       *  Pop up a list of the values of the qualifiers with the given name in the
       *  given feature then select all features that have a qualifier with the
       *  same and value.
       **/
      private void selectMatchingQualifiersHelper (final Feature feature,
                                                   final String name) {
        final Qualifier qualifier;
    
        try {
          qualifier = feature.getQualifierByName (name);
        } catch (InvalidRelationException e) {
          throw new Error ("internal error - unexpected exception: " + e);
        }
    
        if (qualifier == null) {
          throw new Error ("internal error - unexpected null reference");
        }
    
        final StringVector qualifier_values = qualifier.getValues ();
    
        if (qualifier_values.size () == 0) {
          new MessageDialog (getParentFrame (),
                             "qualifier " + name + " has no values in ");
          return;
        }
    
        if (qualifier_values.size () == 1) {
    
    tjc's avatar
    tjc committed
          selectByQualifier (null, name, (String)qualifier_values.elementAt (0));
    
    tjc's avatar
    tjc committed
        } else {
          final ChoiceFrame value_choice_frame =
            new ChoiceFrame ("Select a qualifier value", qualifier_values);
    
          final JComboBox value_choice = value_choice_frame.getChoice ();
    
          value_choice.addItemListener (new ItemListener () {
            public void itemStateChanged (ItemEvent _) {
              selectByQualifier (null, name,
                                 (String) value_choice.getSelectedItem ());
              value_choice_frame.setVisible (false);
              value_choice_frame.dispose ();
            }
          });
    
          value_choice_frame.getOKButton ().addActionListener (new ActionListener () {
            public void actionPerformed (ActionEvent _) {
              selectByQualifier (null, name,
                                 (String) value_choice.getSelectedItem ());
              value_choice_frame.setVisible (false);
              value_choice_frame.dispose ();
            }
          });
    
          value_choice_frame.setVisible (true);
        }    
      }
    
      /**
       *  Select all the features that match the given predicate.
       **/
      private void selectFeaturesByPredicate (final FeaturePredicate predicate) {
        final FeatureVector new_selection_features = new FeatureVector ();
    
        final FeatureEnumeration feature_enum = getEntryGroup ().features ();
    
        while (feature_enum.hasMoreFeatures ()) {
          final Feature current_feature = feature_enum.nextFeature ();
    
          if (predicate.testPredicate (current_feature)) {
            new_selection_features.add (current_feature);
          }
        }
    
        clearSelection ();
    
        getSelection ().add (new_selection_features);
      }
    
      /**
       *  If a range of bases is selected, then select the ORF around those
       *  bases.
       **/
      private void selectOrf () {
        if (!checkForSelectionRange ()) {
          return;
        }
    
        final MarkerRange range = getSelection ().getMarkerRange ();
    
        final Strand strand = getEntryGroup ().getBases ().getForwardStrand ();
    
        final MarkerRange start_orf_range =
          strand.getORFAroundMarker (range.getStart (), true);
    
        /*final*/ Marker end_marker;
    
        // get the marker of the first base of the last codon in the range (we
        // want to keep in the same frame)
        try {
          final int start_end_diff = range.getCount () - 1;
    
          final int mod_length = start_end_diff - start_end_diff % 3;
    
          end_marker = range.getStart ().moveBy (mod_length);
        } catch (OutOfRangeException e) {
          end_marker = range.getStart ();
        }
    
        final MarkerRange end_orf_range =
          strand.getORFAroundMarker (end_marker, true);
    
        MarkerRange new_range = range;
    
        if (start_orf_range != null) {
          new_range = new_range.extendRange (start_orf_range);
        }
    
        if (end_orf_range != null) {
          new_range = new_range.extendRange (end_orf_range);
        }
    
        if (start_orf_range == null && end_orf_range == null &&
            range.getCount () <= 6) {   // 6 == two codons
          new MessageDialog (getParentFrame (),
                             "there is no open reading frame at the selected " +
                             "bases");
          return;
        }
    
        getSelection ().setMarkerRange (new_range);
      }
    
      /**
       *  This method will ask the user for a range of bases (such as 100..200),
       *  using a MarkerRangeRequester component, then selects that range.
       **/
      private void selectBaseRange () {
        final MarkerRangeRequester range_requester =
          new MarkerRangeRequester ("enter a range of bases (eg. 100..200):",
                                    18, "");
    
        final MarkerRangeRequesterListener listener =
          new MarkerRangeRequesterListener () {
            public void actionPerformed (final MarkerRangeRequesterEvent event) {
              final MarkerRange marker_range =
                event.getMarkerRange (getEntryGroup ().getBases ());
    
              getSelection ().setMarkerRange (marker_range);
    
              makeBaseVisible (getSelection ().getStartBaseOfSelection ());
            }
          };
    
        range_requester.addMarkerRangeRequesterListener (listener);
    
        range_requester.setVisible (true);
      }
    
      /**
       *  This method will ask the user for a range of amino acids in a feature
       *  (such as 100..200), using a Requester component, then selects that
       *  range on the sequence.
       **/
      private void selectFeatureAARange () {
        if (!checkForSelectionFeatures (getParentFrame (), getSelection ())) {
          return;
        }
    
        final FeatureVector selected_features = getSelection ().getAllFeatures ();
    
        if (selected_features.size () > 1) {
          new MessageDialog (getParentFrame (), "select only one feature");
          return;
        }
    
        final Feature selected_feature = selected_features.elementAt (0);
    
        final MarkerRangeRequester range_requester =
          new MarkerRangeRequester ("enter a range of amino acids (eg. 100..200):",
                                    18, "");
    
        final MarkerRangeRequesterListener listener =
          new MarkerRangeRequesterListener () {
            public void actionPerformed (final MarkerRangeRequesterEvent event) {
              final Range range = event.getRawRange ();
    
              if (range == null) {
                return;
              }
    
              final int start_position = range.getStart ();
              final int end_position = range.getEnd ();
    
              final int start_pos_in_feature = (start_position - 1) * 3 + 1;
              final int end_pos_in_feature = (end_position - 1) * 3 + 3;
    
              try {
                final Marker start_marker =
                  selected_feature.getPositionInSequence (start_pos_in_feature);
    
                final Marker end_marker =
                  selected_feature.getPositionInSequence (end_pos_in_feature);
    
                final MarkerRange marker_range =
                  new MarkerRange (start_marker.getStrand (),
                                   start_marker.getPosition (),
                                   end_marker.getPosition ());
    
                getSelection ().setMarkerRange (marker_range);
    
                makeBaseVisible (getSelection ().getStartBaseOfSelection ());
              } catch (OutOfRangeException e) {
                new MessageDialog (getParentFrame (),
                                   "amino acid range is out of range " +
                                   "for this feature");
              }
            }
          };
    
        range_requester.addMarkerRangeRequesterListener (listener);
    
        range_requester.setVisible (true);
      }
    
      /**
       *  If there are some selected bases, select the feature in that range
       *  (replacing the orginal selection).  If some features are selected,
       *  select those features that overlap the selected features (and unselect
       *  the original features).
       **/
      private void selectOverlappingFeatures () {
        final MarkerRange selected_marker_range =
          getSelection ().getMarkerRange ();
    
        if (selected_marker_range == null) {
          final FeatureVector selected_features =
            getSelection ().getAllFeatures ();
    
          if (selected_features.size () == 0) {
            new MessageDialog (getParentFrame (), "nothing selected");
            return;
          } else {
            final FeatureVector new_selection = new FeatureVector ();
    
            for (int i = 0 ; i < selected_features.size () ; ++i) {
              final Feature this_feature = selected_features.elementAt (i);
    
              final Range this_feature_raw_range = this_feature.getMaxRawRange ();
    
              try {
                final FeatureVector overlapping_features =
                  getEntryGroup ().getFeaturesInRange (this_feature_raw_range);
    
                for (int overlapping_feature_index = 0 ;
                     overlapping_feature_index < overlapping_features.size () ;
                     ++overlapping_feature_index) {
                  final Feature overlapping_feature =
                    overlapping_features.elementAt (overlapping_feature_index);
    
                  if (!new_selection.contains (overlapping_feature)) {
                    new_selection.add (overlapping_feature);
                  }
                }
              } catch (OutOfRangeException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              }