Skip to content
Snippets Groups Projects
EditMenu.java 118 KiB
Newer Older
  • Learn to ignore specific revisions
  • tjc's avatar
    tjc committed
            StringVector values = feature.getValuesOfQualifier(oldQualifierName);
            Qualifier newQualifier = new Qualifier(newQualifierName, values);
            qualifiers.add(index, newQualifier);
            qualifiers.removeQualifierByName(oldQualifierName);
          }
        }
        catch(EntryInformationException e)
        {
          e.printStackTrace();
        }
    
      }
    
    tjc's avatar
    tjc committed
    
      /**
       *  Remove the qualifier given by qualifier_name from the given features.
       *  Silently ignore features that don't have that qualifier.  Warn the user
       *  about read-only features.
       **/
      private void removeQualifierFromFeatures (final FeatureVector features,
                                                final String qualifier_name) {
        boolean found_read_only = false;
    
        try {
          entry_group.getActionController ().startAction ();
    
          for (int i = 0 ; i < features.size () ; ++i) {
            final Feature this_feature = features.elementAt (i);
            try {
              this_feature.removeQualifierByName (qualifier_name);
            } catch (OutOfDateException _) {
              // ignore
            } catch (EntryInformationException _) {
              // ignore
            } catch (ReadOnlyException _) {
              found_read_only = true;
            }
          }
    
          if (found_read_only) {
            final String message =
              "ignored one or more read-only features";
            new MessageDialog (getParentFrame (), message);
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
    tjc's avatar
    tjc committed
      protected static Vector duplicateGeneFeatures(final JFrame frame,
    
    tjc's avatar
    tjc committed
          final FeatureVector features,
    
          final EntryGroup entry_group) 
      {
    
    tjc's avatar
    tjc committed
        if (getReadOnlyFeatures (features).size () > 0)
    
    tjc's avatar
    tjc committed
          new MessageDialog (frame,
                             "one or more of the selected features is read-only " +
                             "- cannot continue");
    
    tjc's avatar
    tjc committed
          return null;
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
        return GeneUtils.duplicateGeneModel(frame, features, entry_group);
    
    tjc's avatar
    tjc committed
    
      /**
       *  Duplicate the selected Feature objects.  If there are selected segments
       *  then the owning Feature of each segment will be duplicated.
       *  @param frame The JFrame to use for MessageDialog components.
       *  @param selection The Selection containing the features to merge.
       *  @param entry_group Used to get the ActionController for calling
       *    startAction() and endAction().
       **/
    
      protected static void duplicateFeatures (final JFrame frame,
    
    tjc's avatar
    tjc committed
                                     final Selection selection,
                                     final EntryGroup entry_group) {
        try {
          entry_group.getActionController ().startAction ();
    
          if (getReadOnlyFeatures (selection.getAllFeatures ()).size () > 0) {
            new MessageDialog (frame,
                               "one or more of the selected features is read-only " +
                               "- cannot continue");
            return;
          }
    
          if (Options.getOptions ().isNoddyMode ()) {
            final YesNoDialog dialog =
              new YesNoDialog (frame,
                               "Are you sure you want to duplicate the selected " +
                               "features?");
    
            if (!dialog.getResult ()) {
              return;
            }
          } else {
            if (!checkForSelectionFeatures (frame, selection,
                                            100, "really duplicate all (>100) " +
                                            "selected features?")) {
              return;
            }
          }
    
          final FeatureVector features_to_duplicate =
            selection.getAllFeatures ();
    
    
    tjc's avatar
    tjc committed
          FeatureVector chadoGenes = null;
          Vector chadoGeneNames = null;
          for (int i = 0 ; i < features_to_duplicate.size () ; ++i) 
          {
    
    tjc's avatar
    tjc committed
            final Feature this_feature = features_to_duplicate.elementAt (i);
    
    tjc's avatar
    tjc committed
            
            if(this_feature.getEmblFeature() instanceof GFFStreamFeature &&
               ((GFFStreamFeature)this_feature.getEmblFeature()).getChadoGene() != null)
            {
              if(chadoGenes == null)
                chadoGenes = new FeatureVector();
              if(chadoGeneNames == null)
                chadoGeneNames = new Vector();
              
              final String geneName =
                ((GFFStreamFeature)this_feature.getEmblFeature()).getChadoGene().getGeneUniqueName();
              
              if(!chadoGeneNames.contains(geneName))
              {
                chadoGenes.add(this_feature);
                chadoGeneNames.add(geneName);
              }
              continue;
            }
    
    tjc's avatar
    tjc committed
    
    
    tjc's avatar
    tjc committed
            try 
            {
    
              this_feature.duplicate (true);
    
    tjc's avatar
    tjc committed
            } catch (ReadOnlyException e) {
              final String message =
                "one of the selected features (" + this_feature.getIDString () +
                ")  is read only - cannot continue";
              new MessageDialog (frame, message);
              return;
            }
          }
    
    tjc's avatar
    tjc committed
          
          if(chadoGenes != null)
            duplicateGeneFeatures(frame, chadoGenes, entry_group);
    
    tjc's avatar
    tjc committed
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Delete the selected features.
       *  @param frame The JFrame to use for MessageDialog components.
       *  @param selection The Selection containing the features to merge.
       *  @param entry_group Used to get the ActionController for calling
       *    startAction() and endAction().
       **/
    
      protected static void deleteSelectedFeatures (final JFrame frame,
    
    tjc's avatar
    tjc committed
                                          final Selection selection,
    
    tjc's avatar
    tjc committed
          entry_group.getActionController ().startAction ();
    
          final FeatureVector features_to_delete = selection.getAllFeatures ();
          final String feature_count_string;
    
          if (features_to_delete.size () == 1)
    
    tjc's avatar
    tjc committed
            feature_count_string = "the selected feature";
    
    tjc's avatar
    tjc committed
            feature_count_string = features_to_delete.size () + " features";
    
    
          if (Options.getOptions ().isNoddyMode ()) 
          {
          	if(GeneUtils.isDatabaseEntry(entry_group))
          	{
          		Box boption = Box.createVerticalBox();
    
          		JCheckBox delete = new JCheckBox("permanently delete", 
          		  !Options.getOptions().getPropertyTruthValue("set_obsolete_on_delete"));
    
          		boption.add(new JLabel("Make "+feature_count_string+" obsolete?"));
          		boption.add(delete);
          		int res = JOptionPane.showConfirmDialog(frame, 
          				boption, "Make obsolete", JOptionPane.OK_CANCEL_OPTION, 
          				JOptionPane.QUESTION_MESSAGE);
          		if(res == JOptionPane.CANCEL_OPTION)
          			return;
          		
          		// make obsolete rather than permanently delete
          		if(!delete.isSelected())
          		{
          			for(int i=0; i<features_to_delete.size(); i++)
          			{
          				final Feature currentFeature = features_to_delete.elementAt(i);
          				try
    							{
    								currentFeature.setQualifier(new Qualifier("isObsolete", "true"));
    	              PropertiesPanel.updateObsoleteSettings(
    	      						(GFFStreamFeature)currentFeature.getEmblFeature());
    							} 
          				catch (Exception e)
    							{
    								e.printStackTrace();
    							} 	
          			}
          			return;
          		}
          	}
          	if (!checkForSelectionFeatures (frame, selection, 0,
    
    tjc's avatar
    tjc committed
                                            "really delete " +
    
    tjc's avatar
    tjc committed
          }
    
          // clear the selection now so that it doesn't need to be updated as each
          // feature is deleted
          selection.clear ();
    
    
          while (features_to_delete.size () > 0) 
          {
    
    tjc's avatar
    tjc committed
            // delete in reverse order for speed
    
            final Feature current_selection_feature =
              features_to_delete.lastElement ();
    
            features_to_delete.removeElementAt (features_to_delete.size () - 1);
    
    
    tjc's avatar
    tjc committed
              current_selection_feature.removeFromEntry ();
    
    tjc's avatar
    tjc committed
              selection.set (current_selection_feature);
    
    
              if (features_to_delete.size () == 1) 
              {
    
    tjc's avatar
    tjc committed
                final String message =
                  "the selected feature (" +
                  current_selection_feature.getIDString () +
                  ") is read only - cannot continue";
                new MessageDialog (frame, message);
    
    tjc's avatar
    tjc committed
                final String message =
                  "one of the selected features (" +
                  current_selection_feature.getIDString () +
                  ") is read only - cannot continue";
                new MessageDialog (frame, message);
              }
    
              features_to_delete.add (current_selection_feature);
    
              // reset the select so that the user can see what it was
              selection.set (features_to_delete);
    
              return;
            }
          }
    
    tjc's avatar
    tjc committed
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Delete the selected feature segments.
       **/
      private void deleteSelectedSegments () {
        try {
          entry_group.getActionController ().startAction ();
    
          final FeatureSegmentVector segments_to_delete =
    
    tjc's avatar
    tjc committed
            (FeatureSegmentVector) getSelection ().getAllSegments ().clone ();
    
    tjc's avatar
    tjc committed
    
          if (Options.getOptions ().isNoddyMode ()) {
            // 0 means always popup a YesNoDialog
            if (!checkForSelectionFeatureSegments (0, "really delete " +
                                                   (segments_to_delete.size ()==1 ?
                                                    "the selected exon?" :
                                                    segments_to_delete.size () +
                                                    " exons?"))) {
              return;
            }
          }
    
          for (int i = 0 ; i < segments_to_delete.size () ; ++i) {
            final FeatureSegment selection_segment =
              segments_to_delete.elementAt (i);
    
            try {
              getSelection ().remove (selection_segment);
              selection_segment.removeFromFeature ();
            } catch (ReadOnlyException e) {
              final String message =
                "one of the selected exons (in " +
                selection_segment.getFeature ().getIDString () +
                ") is in a read only - cannot continue";
              new MessageDialog (getParentFrame (), message);
            } catch (LastSegmentException e) {
              final String message =
                "the last exon in this feature: " +
                selection_segment.getFeature ().getIDString () +
                " cannot be removed (all features must have at least one exon)";
              new MessageDialog (getParentFrame (), message);
            }
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Remove all introns from the selected features.
       **/
      private void removeIntrons () {
        if (!checkForSelectionFeatures ()) {
          return;
        }
    
        boolean found_read_only = false;
    
        try {
          entry_group.getActionController ().startAction ();
    
          final FeatureVector features = getSelection ().getAllFeatures ();
    
          for (int i = 0 ; i < features.size () ; ++i) {
            final Feature this_feature = features.elementAt (i);
            try {
              final RangeVector new_ranges = new RangeVector ();
              final Range new_range = this_feature.getMaxRawRange ();
              new_ranges.add (new_range);
              final Location old_location = this_feature.getLocation ();
              final Location new_location =
                new Location (new_ranges, old_location.isComplement ());
              this_feature.setLocation (new_location);
            } catch (OutOfRangeException e) {
              throw new Error ("internal error - unexpected exception: " + e);
            } catch (ReadOnlyException _) {
              found_read_only = true;
            }
          }
    
          if (found_read_only) {
            final String message =
              "ignored one or more read-only features";
            new MessageDialog (getParentFrame (), message);
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Move the given features to the given destination entry.
       **/
      private void moveFeatures (final FeatureVector features,
                                 final Entry destination_entry) {
        try {
          entry_group.getActionController ().startAction ();
    
          if (features.size () == 0) {
            return;
          }
    
          final FeatureVector read_only_features =
            getReadOnlyFeatures (features);
    
          if (read_only_features.size () > 0) {
            final String message =
              (features.size () == 1 ?
               "the selected feature (" +
               read_only_features.elementAt (0).getIDString () +
               ") is read only " :
               "some of the selected features (eg. " +
               read_only_features.elementAt (0).getIDString () +
               ") are read only - ")  +
              "cannot continue";
            new MessageDialog (getParentFrame (), message);
            return;
          }
    
      FEATURES:
          for (int i = 0 ; i < features.size () ; ++i) {
            final Feature this_feature = features.elementAt (i);
    
            // check that we don't loop forever (perhaps due to bugs in
            // handleOpenException())
            final int MAX_COUNT = 100;
    
            int count = 0;
    
            while (count++ < MAX_COUNT) {
              try {
                this_feature.moveTo (destination_entry, false);
                continue FEATURES;
              } catch (OutOfRangeException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              } catch (EntryInformationException e) {
                final EntryInformation dest_entry_information =
                  destination_entry.getEntryInformation ();
                dest_entry_information.fixException (e);
                continue;
              } catch (ReadOnlyException e) {
                final String message =
                  "either the source or destination for one of the features is " +
                  "read only - cannot continue";
                new MessageDialog (getParentFrame (), message);
                return;
              }
            }
    
            final String message =
              "internal error while copying";
            new MessageDialog (getParentFrame (), message);
    
            throw new Error ("internal error in EditMenu.copyFeatures() - infinite loop");
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Copy the given features to the given destination entry.
       **/
      private void copyFeatures (final FeatureVector features,
                                 final Entry destination_entry) {
        try {
          entry_group.getActionController ().startAction ();
    
      FEATURES:
          for (int i = 0 ; i < features.size () ; ++i) {
            final Feature this_feature = features.elementAt (i);
    
            // check that we don't loop forever (perhaps due to bugs in
            // handleOpenException())
            final int MAX_COUNT = 100;
    
            int count = 0;
    
            while (count++ < MAX_COUNT) {
              try {
                this_feature.copyTo (destination_entry);
                continue FEATURES;
              } catch (OutOfRangeException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              } catch (EntryInformationException e) {
                final EntryInformation dest_entry_information =
                  destination_entry.getEntryInformation ();
                dest_entry_information.fixException (e);
                continue;
              } catch (ReadOnlyException e) {
                final String message =
                  "the destination entry is read only - cannot continue";
                new MessageDialog (getParentFrame (), message);
                return;
              }
            }
    
            final String message = "internal error while copying";
            new MessageDialog (getParentFrame (), message);
    
            throw new Error ("internal error in EditMenu.copyFeatures() - " +
                               "infinite loop");
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Calls fixStopCodon () on each selected feature.
       **/
      private void fixStopCodons () {
        try {
          entry_group.getActionController ().startAction ();
    
          if (!checkForSelectionFeatures ()) {
            return;
          }
    
          // features that can't be fixed
          final FeatureVector bad_features = new FeatureVector ();
    
          final FeatureVector features_to_fix = getSelection ().getAllFeatures ();
    
          for (int i = 0 ; i < features_to_fix.size () ; ++i) {
            final Feature selection_feature = features_to_fix.elementAt (i);
    
    
    tjc's avatar
    tjc committed
            if (!selection_feature.isCDS() &&
                !(selection_feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))) {
    
    tjc's avatar
    tjc committed
              final String message =
                "Warning: some of the selected features are not coding features. " +
                "Continue?";
    
              final YesNoDialog yes_no_dialog =
                new YesNoDialog (getParentFrame (), message);
    
              if (yes_no_dialog.getResult ()) {
                break;
              } else {
                return;
              }
            }
          }
    
          for (int i = 0 ; i < features_to_fix.size () ; ++i) {
            final Feature selection_feature = features_to_fix.elementAt (i);
    
            try {
              if (!selection_feature.fixStopCodon ()) {
                bad_features.add (selection_feature);
              }
            } catch (ReadOnlyException e) {
              final String message =
                "one of the entries is read only - cannot continue";
              new MessageDialog (getParentFrame (), message);
              break;
            }
          }
    
          if (bad_features.size () > 0) {
            // select the bad feature
            getSelection ().set (bad_features);
    
            final String message =
              "Warning: could not fix the stop codon for some of the features. " +
              "View them now?";
    
            final YesNoDialog yes_no_dialog =
              new YesNoDialog (getParentFrame (), message);
    
            if (yes_no_dialog.getResult ()) {
              final FeaturePredicate predicate =
                new FeatureFromVectorPredicate (bad_features);
    
              final String filter_name =
                "features that can't be fixed (filtered from: " +
                getParentFrame ().getTitle () + ")";
    
              final FilteredEntryGroup filtered_entry_group =
                new FilteredEntryGroup (entry_group, predicate, filter_name);
    
              final FeatureListFrame feature_list_frame =
                new FeatureListFrame (filter_name,
                                      getSelection (),
                                      goto_event_source, filtered_entry_group,
                                      base_plot_group);
    
              feature_list_frame.setVisible (true);
            }
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Calls Feature.trimStart () on all selected Feature objects.
       *  @param frame The JFrame to use for MessageDialog components.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param entry_group Used to get the ActionController for calling
       *    startAction().
       *  @param trim_to_any If true then the features will be trimmed to ATG, GTG
       *    or TTG, otherwise the features will be trimmed to ATG only.
       *  @param trim_to_next If true then the features will be trimmed to the
       *    next start codon (dependent on trim_to_any) regardless of whether the
       *    feature currently start on a start codon.  If false then the feature
       *    will only be trimmed if the feature doesn't start on a start codon.
       **/
    
    tjc's avatar
    tjc committed
      protected static void trimSelected (final JFrame frame,
    
    tjc's avatar
    tjc committed
                                       final Selection selection,
                                       final EntryGroup entry_group,
                                       final boolean trim_to_any,
                                       final boolean trim_to_next) {
        try {
          entry_group.getActionController ().startAction ();
    
          if (!checkForSelectionFeatures (frame, selection)) {
            return;
          }
    
          final FeatureVector features_to_trim = selection.getAllFeatures ();
    
          // this will contain the features that could not be trimmed
          final FeatureVector failed_features = new FeatureVector ();
    
          for (int i = 0 ; i < features_to_trim.size () ; ++i) {
            final Feature selection_feature = features_to_trim.elementAt (i);
    
            try {
              if (!selection_feature.trimStart (trim_to_any, trim_to_next)) {
                failed_features.add (selection_feature);
              }
            } catch (ReadOnlyException e) {
              final String message =
                "one or more of the of the selected features are read only " +
                "- cannot continue";
              new MessageDialog (frame, message);
              break;
            }
          }
    
          if (failed_features.size () > 0) {
            selection.set (failed_features);
    
            if (failed_features.size () == 1) {
              final String message = "could not trim the feature";
    
              new MessageDialog (frame, message);
    
            } else {
              final String message =
                "some features could not be trimmed (they are now selected)";
    
              new MessageDialog (frame, message);
            }
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Extend the selected segments/features so that they reach to the start or
       *  end of their containing ORF.
       *  @param frame The JFrame to use for MessageDialog components.
       *  @param selection The Selection that the commands in the menu will
       *    operate on.
       *  @param entry_group Used to get the ActionController for calling
       *    startAction() and endAction().
       *  @param extend_to_next_stop If true the feature is extended to the next
       *    stop codon (but it won't include the next stop).  If false the feature
       *    is extended to the previous stop codon (but it won't include the
       *    previous stop).
       **/
    
    tjc's avatar
    tjc committed
      protected static void extendToORF(final JFrame frame,
    
                                     final Selection selection,
                                     final EntryGroup entry_group,
                                     final boolean extend_to_next_stop) 
      {
    
    tjc's avatar
    tjc committed
        try {
          entry_group.getActionController ().startAction ();
    
          if (!checkForSelectionFeatures (frame, selection)) {
            return;
          }
    
          final FeatureVector features_to_extend = selection.getAllFeatures ();
    
          for (int i = 0 ; i < features_to_extend.size () ; ++i) {
            final Feature selection_feature = features_to_extend.elementAt (i);
    
            if (selection_feature.isReadOnly ()) {
              final String message =
                "one or more of the of the selected features are read only " +
                "- cannot continue";
              new MessageDialog (frame, message);
              break;
            }
    
            if (selection_feature.getSegments ().size () < 1) {
              continue;
            }
    
            final FeatureSegmentVector feature_segments =
              selection_feature.getSegments ();
    
            if (feature_segments.size () == 0) {
              continue;
            }
    
            final Strand strand = selection_feature.getStrand ();
    
            if (extend_to_next_stop) {
    
    tjc's avatar
    tjc committed
              
              if(!(selection_feature.getEmblFeature() instanceof GFFStreamFeature))
              {
                if(selection_feature.hasValidStopCodon()) 
                  continue;
              }
              else
              {
                if(selection_feature.hasValidStopCodon(true)) 
                  continue;
    
    tjc's avatar
    tjc committed
              }
    
              final Marker feature_end_marker =
                selection_feature.getLastBaseMarker ();
    
              Marker end_marker_copy = null;
    
              // get the marker of the first base of the last codon in the range
              // (we want to keep in the same frame)
              try {
                if (selection_feature.getBaseCount () == 1) {
                  end_marker_copy = feature_end_marker;
                } else {
                  if (selection_feature.getBaseCount () == 2) {
                    end_marker_copy = feature_end_marker.moveBy (-1);
                  } else {
                    // go to the start of the codon
                    end_marker_copy = feature_end_marker.moveBy (-2);
                  }
                }
    
                // adjust for /codon_start
                final int frame_shift =
                  selection_feature.getCodonStart () - 1;
    
                // the number of bases from the start of translation to the
                // end of the feature
                final int bases_from_start_pos_mod_3 =
                  (3 + selection_feature.getBaseCount () - frame_shift) % 3;
    
                end_marker_copy =
                  end_marker_copy.moveBy (-bases_from_start_pos_mod_3);
              } catch (OutOfRangeException e) {
                end_marker_copy = feature_end_marker;
              }
    
              final MarkerRange end_orf_range =
                strand.getORFAroundMarker (end_marker_copy, true);
    
              if (end_orf_range == null) {
                // end_marker_copy is at the start base of a stop codon
                continue;
              }
    
              final Marker new_end_marker = end_orf_range.getEnd ();
    
              try {
                feature_end_marker.setPosition (new_end_marker.getPosition ());
              } catch (OutOfRangeException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              }
    
            } else {
              final AminoAcidSequence translation =
                selection_feature.getTranslation ();
    
              if (translation.length () > 0) {
                final char first_aa = translation.elementAt (0);
    
                if (AminoAcidSequence.isStopCodon (first_aa)) {
                  continue;
                }
              }
    
              final Marker feature_start_marker =
                selection_feature.getFirstBaseMarker ();
    
              Marker start_marker_copy = feature_start_marker;
    
              final int frame_shift =
                selection_feature.getCodonStart () - 1;
    
              if (frame_shift != 0) {
                try {
                  start_marker_copy =
                    feature_start_marker.moveBy (frame_shift);
                } catch (OutOfRangeException e) {
                  // ignore and hope for the best
                }
              }
    
              final MarkerRange start_orf_range =
                strand.getORFAroundMarker (start_marker_copy, true);
    
              final Marker new_start_marker = start_orf_range.getStart ();
    
              try {
                feature_start_marker.setPosition (new_start_marker.getPosition ());
                selection_feature.removeQualifierByName ("codon_start");
              } catch (EntryInformationException _) {
                // ignore - if we can't remove codon_start, then it won't have
                // been there to start with
              } catch (OutOfDateException _) {
                // ignore
              } catch (ReadOnlyException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              } catch (OutOfRangeException e) {
                throw new Error ("internal error - unexpected exception: " + e);
              }
            }
          }
        } finally {
          entry_group.getActionController ().endAction ();
        }
      }
    
      /**
       *  Reverse and complement the sequence and all the features in all Entry
       *  objects.
       **/
    
      private void reverseAndComplement () 
      {
        if (getEntryGroup ().isReadOnly ())
        {
    
    tjc's avatar
    tjc committed
          final String message =
            "one or more of the entries or features are read only - " +
            "cannot continue";
          new MessageDialog (getParentFrame (), message);
          return;
        }
    
        final YesNoDialog dialog =
          new YesNoDialog (getParentFrame (),
                           "Are you sure you want to reverse complement all " +
                           "entries?");
    
    
        if (!dialog.getResult ())
    
    tjc's avatar
    tjc committed
          return;
    
    
        try
        {  
          if(getEntryGroup().getBases().getSequence() instanceof RawStreamSequence)
            setFastaHeaderPositionsOnReverseComplement(
                (RawStreamSequence) getEntryGroup().getBases().getSequence());
          
    
    tjc's avatar
    tjc committed
          getEntryGroup ().reverseComplement ();
          makeSelectionStartVisible ();
    
        } 
        catch (ReadOnlyException e) 
        {
    
    tjc's avatar
    tjc committed
          final String message =
            "one of the entries is read only - cannot continue";
          new MessageDialog (getParentFrame (), message);
          return;
        }
      }
    
    
      /**
       * Set the fasta header positions.
       * @param sequence
       */
      private void setFastaHeaderPositionsOnReverseComplement(final RawStreamSequence sequence)
      {
        // find all fasta_record features
        final FeaturePredicate key_predicate_contig
              = new FeatureKeyQualifierPredicate(new Key("fasta_record"),
                                                 null, // match any qialifier
                                                 false);
    
        final RangeVector contigRanges = new RangeVector();
        for(int i=0; i<getEntryGroup().getAllFeatures().size(); i++)
        {
          uk.ac.sanger.artemis.Feature contig = 
               getEntryGroup().getAllFeatures().elementAt(i);
          if(key_predicate_contig.testPredicate(contig))
            contigRanges.add(contig.getLocation().getTotalRange());
        }
        sequence.setFastaHeaderPositionsOnReverseComplement(contigRanges);  
      }
      
    
    tjc's avatar
    tjc committed
      /**
       *  Delete the selected bases after asking the user for confimation.
       **/
    
    tjc's avatar
    tjc committed
      private boolean deleteSelectedBases (final String description) {
    
    tjc's avatar
    tjc committed
        if (!checkForSelectionRange ()) {
    
    tjc's avatar
    tjc committed
          return false;
    
    tjc's avatar
    tjc committed
        }
    
        final MarkerRange marker_range = getSelection ().getMarkerRange ();
    
        if (marker_range.getCount () == getEntryGroup ().getSequenceLength ()) {
          new MessageDialog (getParentFrame (), "You can't delete every base");
    
    tjc's avatar
    tjc committed
          return false;
    
    tjc's avatar
    tjc committed
        }
    
        if (getEntryGroup ().isReadOnly ()) {
          new MessageDialog (getParentFrame (),
                             "one of the current entries or features is " +
                             "read-only - connot continue");
    
    tjc's avatar
    tjc committed
          return false;
    
    tjc's avatar
    tjc committed
        }
    
        final Range raw_range = marker_range.getRawRange ();
    
        final FeatureVector features_in_range;
    
        final EntryVector old_active_entries =
          getEntryGroup ().getActiveEntries ();
    
        // make all the entries active so that getFeaturesInRange () gets
        // everything
        for (int i = 0 ; i < getEntryGroup ().size () ; ++i) {
          getEntryGroup ().setIsActive (i, true);
        }
    
        try {
          features_in_range =
            getEntryGroup ().getFeaturesInRange (raw_range);
        } catch (OutOfRangeException e) {
          throw new Error ("internal error - unexpected exception: " + e);
        }
    
        if (features_in_range.size () != 0) {
          final FeatureVector read_only_features =
            getReadOnlyFeatures (features_in_range);
    
          if (read_only_features.size () > 0) {
            getSelection ().set (read_only_features);
            final String message =
              "one or more of the features in the selected range are " +
              "read only - cannot continue";
            new MessageDialog (getParentFrame (), message);
            getSelection ().setMarkerRange (marker_range);
    
    tjc's avatar
    tjc committed
            return false;
    
    tjc's avatar
    tjc committed
          }
    
          for (int feature_index = 0 ;
               feature_index < features_in_range.size () ;
               ++feature_index) {
            final Feature this_feature =
              features_in_range.elementAt (feature_index);
    
            final FeatureSegmentVector segments = this_feature.getSegments ();
    
            for (int i = 0 ; i < segments.size () ; ++i) {
              final FeatureSegment this_segment = segments.elementAt (i);
    
              final Range this_segment_range = this_segment.getRawRange ();
    
              if (raw_range.getStart () <= this_segment_range.getStart () &&
                  raw_range.getEnd () >= this_segment_range.getStart () ||
                  raw_range.getStart () <= this_segment_range.getEnd () &&
                  raw_range.getEnd () >= this_segment_range.getEnd ()) {
                new MessageDialog (getParentFrame (),
                                   "the selected range overlaps the " +
                                   "start or end of an exon - cannot continue");
    
    tjc's avatar
    tjc committed
                return false;
    
    tjc's avatar
    tjc committed
              }
            }
          }
        }
    
        // reset the EntryGroup to the state it was in originally
        for (int i = 0 ; i < getEntryGroup ().size () ; ++i) {
          final Entry this_entry = getEntryGroup ().elementAt (i);
          final boolean old_active_flag =
            old_active_entries.contains (this_entry);
          getEntryGroup ().setIsActive (i, old_active_flag);
        }
    
        if (Options.getOptions ().isNoddyMode ()) {
          final YesNoDialog dialog =
    
    tjc's avatar
    tjc committed
            new YesNoDialog (getParentFrame (), description);
    
    tjc's avatar
    tjc committed
          if (!dialog.getResult ()) {
    
    tjc's avatar
    tjc committed
            return false;
    
    tjc's avatar
    tjc committed
          }
        }
    
        try {
          getSelection ().setMarkerRange (null);
    
          // deleteRange () is static and uses the strand reference from the
          // MarkerRange to decide which Strand to edit
          Strand.deleteRange (marker_range);
        } catch (ReadOnlyException e) {
          getSelection ().setMarkerRange (marker_range);
    
          new MessageDialog (getParentFrame (),
                             "the bases are read only - cannot delete");
    
    tjc's avatar
    tjc committed
          return false;
    
    tjc's avatar
    tjc committed
        }
    
    tjc's avatar
    tjc committed
        return true;
    
    tjc's avatar
    tjc committed
      }
    
      /**
       *  Ask the user for some bases and then add them at the start of the
       *  selected range.
       **/
      private void addBases () {
        if (!checkForSelectionRange ()) {
          return;
        }
    
        if (getEntryGroup ().isReadOnly ()) {
          new MessageDialog (getParentFrame (),
                             "one of the current entries or features is " +
                             "read-only - connot continue");
          return;
        }
    
        final MarkerRange range = getSelection ().getMarkerRange ();
    
        final TextRequester text_requester =
          new TextRequester ("enter the bases to insert before base " +
                             range.getStart ().getPosition () +
                             (range.isForwardMarker () ?
                              " on the forward strand" :
                              " on the reverse strand") + ":",
                             18, "");