Newer
Older
/* EditMenu.java
*
* created: Thu Dec 3 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/EditMenu.java,v 1.27 2007-09-06 10:22:21 tjc Exp $
**/
package uk.ac.sanger.artemis.components;
import uk.ac.sanger.artemis.*;
import uk.ac.sanger.artemis.sequence.*;
import uk.ac.sanger.artemis.util.*;
import uk.ac.sanger.artemis.components.genebuilder.GeneBuilderFrame;
import uk.ac.sanger.artemis.components.genebuilder.GeneViewerPanel;
import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
import uk.ac.sanger.artemis.io.Range;
import uk.ac.sanger.artemis.io.RangeVector;
import uk.ac.sanger.artemis.io.Key;
import uk.ac.sanger.artemis.io.Location;
import uk.ac.sanger.artemis.io.Qualifier;
import uk.ac.sanger.artemis.io.QualifierVector;
import uk.ac.sanger.artemis.io.InvalidRelationException;
import uk.ac.sanger.artemis.io.EntryInformation;
import uk.ac.sanger.artemis.io.EntryInformationException;
import uk.ac.sanger.artemis.io.OutOfDateException;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
/**
* A menu with editing commands.
*
* @author Kim Rutherford
* @version $Id: EditMenu.java,v 1.27 2007-09-06 10:22:21 tjc Exp $
implements EntryGroupChangeListener, EntryChangeListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* 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 = null;
/**
* The BasePlotGroup object that was passed to the constructor.
**/
private BasePlotGroup base_plot_group = null;
/**
* Create a new EditMenu object.
* @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 new features/entries will
* be added.
* @param base_plot_group The BasePlotGroup associated with this JMenu -
* needed to call getCodonUsageAlgorithm()
* @param menu_name The name of the new menu.
**/
public EditMenu(final JFrame frame,
final Selection selection,
final GotoEventSource goto_event_source,
final EntryGroup entry_group,
final BasePlotGroup base_plot_group,
{
super(frame, menu_name, selection);
this.entry_group = entry_group;
this.goto_event_source = goto_event_source;
this.base_plot_group = base_plot_group;
getEntryGroup().addEntryGroupChangeListener(this);
getEntryGroup().addEntryChangeListener(this);
refreshMenu();
}
/**
* Create a new EditMenu object and use "Edit" as the menu name.
* @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 new features/entries will
* be added.
* @param base_plot_group The BasePlotGroup associated with this JMenu -
* needed to call getCodonUsageAlgorithm()
**/
public EditMenu(final JFrame frame,
final Selection selection,
final GotoEventSource goto_event_source,
final EntryGroup entry_group,
final BasePlotGroup base_plot_group,
final DisplayComponent owner)
{
this(frame, selection, goto_event_source, entry_group,
}
/**
* The shortcut for Edit Selected Features.
**/
final static KeyStroke EDIT_FEATURES_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_E,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); //InputEvent.CTRL_MASK);
final static public int EDIT_FEATURES_KEY_CODE = KeyEvent.VK_E;
/**
* The shortcut for Merge Selected Features.
**/
final static KeyStroke MERGE_FEATURES_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_M,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
final static public int MERGE_FEATURES_KEY_CODE = KeyEvent.VK_M;
/**
* The shortcut for Duplicate Selected Features.
**/
final static KeyStroke DUPLICATE_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_D,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
final static public int DUPLICATE_KEY_CODE = KeyEvent.VK_D;
/**
* The shortcut for Delete Selected Features.
**/
final static KeyStroke DELETE_FEATURES_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
final static public int DELETE_FEATURES_KEY_CODE = KeyEvent.VK_DELETE;
/**
* The shortcut for Trim Selected Features.
**/
final static KeyStroke TRIM_FEATURES_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_T,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
final static public int TRIM_FEATURES_KEY_CODE = KeyEvent.VK_T;
/**
* The shortcut for Trim Selected Features To Next Any.
**/
final static KeyStroke TRIM_FEATURES_TO_NEXT_ANY_KEY =
KeyStroke.getKeyStroke(KeyEvent.VK_Y,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
final static public int TRIM_FEATURES_TO_NEXT_ANY_KEY_CODE = KeyEvent.VK_Y;
/**
* The shortcut for Extend to Previous Stop Codon.
**/
final static public int EXTEND_TO_PREVIOUS_STOP_CODON_KEY_CODE =
KeyEvent.VK_Q;
final static KeyStroke EXTEND_TO_PREVIOUS_STOP_CODON_KEY =
makeMenuKeyStroke(EXTEND_TO_PREVIOUS_STOP_CODON_KEY_CODE);
/**
* The shortcut for Undo.
**/
final static public int UNDO_KEY_CODE = KeyEvent.VK_U;
final static KeyStroke UNDO_KEY =
KeyStroke.getKeyStroke(UNDO_KEY_CODE,
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); // InputEvent.CTRL_MASK);
/**
* Implementation of the EntryGroupChangeListener interface. We listen to
* EntryGroupChange events so that we can update the display if entries
* are added or deleted.
**/
public void entryGroupChanged(final EntryGroupChangeEvent event)
{
switch(event.getType())
{
case EntryGroupChangeEvent.ENTRY_ADDED:
case EntryGroupChangeEvent.ENTRY_DELETED:
case EntryGroupChangeEvent.ENTRY_INACTIVE:
case EntryGroupChangeEvent.ENTRY_ACTIVE:
case EntryGroupChangeEvent.NEW_DEFAULT_ENTRY:
refreshMenu();
break;
}
}
/**
* Implementation of the EntryChangeListener interface.
**/
public void entryChanged(final EntryChangeEvent event)
{
if(event.getType() == EntryChangeEvent.NAME_CHANGED)
refreshMenu();
}
/**
* Update the menus to the reflect the current contents of the EntryGroup.
**/
private void refreshMenu()
{
removeAll();
final JMenuItem undo_item = new JMenuItem("Undo");
undo_item.setAccelerator(UNDO_KEY);
undo_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
undo(getParentFrame(), getSelection(), getEntryGroup());
final JMenuItem contig_reordering = new JMenuItem("Contig Reordering");
contig_reordering.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
FeatureDisplay display = (FeatureDisplay)owner;
FeatureVector contig_features = display.getContigs();
final JFrame frame = new JFrame("Contig Tool");
final ContigTool ct = new ContigTool(contig_features,
(FeatureDisplay)owner, jsp,
getSelection());
jsp.setViewportView(ct);
jsp.getViewport().setBackground(Color.white);
jsp.setPreferredSize(new Dimension(display.getWidth(),
ct.getPreferredSize().height+
jsp.getVerticalScrollBar().getPreferredSize().height));
frame.getContentPane().add(jsp, BorderLayout.CENTER);
frame.getContentPane().add(ct.getStatusBar(),
BorderLayout.SOUTH);
frame.pack();
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
getSelection().removeSelectionChangeListener(ct);
frame.dispose();
}
});
final JMenuItem edit_feature_item = new JMenuItem("Edit Selected Features");
edit_feature_item.setAccelerator(EDIT_FEATURES_KEY);
edit_feature_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
editSelectedFeatures(getParentFrame(), getEntryGroup(),
getSelection(), goto_event_source);
final JMenuItem edit_subsequence_item = new JMenuItem("Edit Subsequence (and Features)");
edit_subsequence_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
editSubSequence();
final JMenuItem add_qualifiers_item = new JMenuItem("Change Qualifiers Of Selected ...");
add_qualifiers_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
addQualifiers(getParentFrame(), getSelection());
final JMenuItem remove_qualifier_item = new JMenuItem("Remove Qualifier Of Selected ...");
remove_qualifier_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
removeQualifier(getParentFrame(), getSelection());
final JMenuItem convert_qualifier_item = new JMenuItem("Convert Qualifier Of Selected ...");
convert_qualifier_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
convertQualifier(getParentFrame(), getSelection());
}
});
final JMenuItem merge_features_item = new JMenuItem("Merge Selected Features");
merge_features_item.setAccelerator(MERGE_FEATURES_KEY);
merge_features_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
mergeFeatures(getParentFrame(), getSelection(), getEntryGroup());
final JMenuItem unmerge_feature_item = new JMenuItem("Unmerge Selected Feature");
unmerge_feature_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
unmergeFeature(getParentFrame(), getSelection(), getEntryGroup());
final JMenuItem unmerge_all_feature_item = new JMenuItem("Unmerge All Feature Segments");
unmerge_all_feature_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
unmergeAllFeature(getParentFrame(), getSelection(), getEntryGroup());
}
});
final JMenuItem duplicate_item = new JMenuItem("Duplicate Selected Features");
duplicate_item.setAccelerator(DUPLICATE_KEY);
duplicate_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
duplicateFeatures(getParentFrame(), getSelection(),
getEntryGroup());
final JMenuItem delete_features_item = new JMenuItem("Delete Selected Features");
delete_features_item.setAccelerator(DELETE_FEATURES_KEY);
delete_features_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
deleteSelectedFeatures(getParentFrame(), getSelection(),
getEntryGroup());
final JMenuItem delete_segments_item = new JMenuItem("Delete Selected Exons");
delete_segments_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
deleteSelectedSegments();
final JMenuItem delete_introns_item =
new JMenuItem("Remove Introns of Selected Features");
delete_introns_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
removeIntrons();
final JMenuItem edit_header_item = new JMenuItem("Edit Header Of Default Entry");
edit_header_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
editHeader();
final JMenu move_features_menu = new JMenu("Move Selected Features To");
final JMenu copy_features_menu = new JMenu("Copy Selected Features To");
if(entry_group == null || getEntryGroup().size() == 0)
{
move_features_menu.add(new JMenuItem("(No Entries Currently)"));
copy_features_menu.add(new JMenuItem("(No Entries Currently)"));
}
else
{
for(int i = 0 ; i < getEntryGroup().size() ; ++i)
{
final Entry this_entry = getEntryGroup().elementAt(i);
String entry_name = this_entry.getName();
if(entry_name == null)
final JMenuItem move_to_item = new JMenuItem(entry_name);
move_to_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
// unselect, move, then reselect (for speed)
final FeatureVector selected_features =
getSelection().getAllFeatures();
getSelection().clear();
moveFeatures(selected_features, this_entry);
getSelection().set(selected_features);
move_features_menu.add(move_to_item);
final JMenuItem copy_to_item = new JMenuItem(entry_name);
copy_to_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
copyFeatures(getSelection().getAllFeatures(), this_entry);
copy_features_menu.add(copy_to_item);
final JMenuItem trim_to_any_item = new JMenuItem("Trim Selected Features To Any");
trim_to_any_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event) {
EditMenu.trimSelected(getParentFrame(), getSelection(),
getEntryGroup(), true, false);
final JMenuItem trim_item = new JMenuItem("Trim Selected Features To Met");
trim_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
EditMenu.trimSelected(getParentFrame(), getSelection(),
getEntryGroup(), false, false);
final JMenuItem trim_to_next_any_item =
new JMenuItem("Trim Selected Features To Next Any");
trim_to_next_any_item.setAccelerator(TRIM_FEATURES_TO_NEXT_ANY_KEY);
trim_to_next_any_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
EditMenu.trimSelected(getParentFrame(), getSelection(),
getEntryGroup(), true, true);
final JMenuItem trim_to_next_item = new JMenuItem("Trim Selected Features To Next Met");
trim_to_next_item.setAccelerator(TRIM_FEATURES_KEY);
trim_to_next_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
EditMenu.trimSelected(getParentFrame(), getSelection(),
getEntryGroup(), false, true);
final JMenuItem extend_to_prev_stop_item =
new JMenuItem("Extend to Previous Stop Codon");
extend_to_prev_stop_item.setAccelerator(EXTEND_TO_PREVIOUS_STOP_CODON_KEY);
extend_to_prev_stop_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
extendToORF(getParentFrame(), getSelection(),
getEntryGroup(), false);
final JMenuItem extend_to_next_stop_item = new JMenuItem("Extend to Next Stop Codon");
extend_to_next_stop_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
extendToORF(getParentFrame(), getSelection(),
getEntryGroup(), true);
final JMenuItem fix_stop_codons_item = new JMenuItem("Fix Stop Codons");
fix_stop_codons_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
fixStopCodons();
final JMenuItem extend_to_next_stop_and_fix_item = new JMenuItem("Extend to Next Stop Codon and Fix");
extend_to_next_stop_and_fix_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
extendToORF(getParentFrame(), getSelection(),
getEntryGroup(), true);
fixStopCodons();
}
});
final JMenuItem auto_gene_name_item = new JMenuItem("Automatically Create Gene Names");
auto_gene_name_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
autoGeneName();
final JMenuItem fix_gene_names_item = new JMenuItem("Fix Gene Names");
fix_gene_names_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
fixGeneNames(getParentFrame(), getEntryGroup(),
getSelection());
final JMenuItem reverse_complement_item = new JMenuItem("Reverse And Complement");
reverse_complement_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
reverseAndComplement();
final JMenuItem reverse_complement_range_item = new JMenuItem("Reverse And Complement Selected Contig");
reverse_complement_range_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if(getEntryGroup().isReadOnly())
{
final String message =
"one or more of the entries or features are read only - " +
"cannot continue";
new MessageDialog(getParentFrame(), message);
return;
}
final FeatureVector selected_features = getSelection().getAllFeatures();
if(selected_features.size() == 1)
{
final Feature selection_feature = selected_features.elementAt(0);
final YesNoDialog dialog =
new YesNoDialog (getParentFrame (),
"Are you sure you want to reverse complement this " +
"region "+ selection_feature.getFirstBase()+".."+
selection_feature.getLastBase()+"?");
if(!dialog.getResult())
return;
try
{
getEntryGroup().getBases().reverseComplement(selection_feature);
}
catch(ReadOnlyException roe)
{
final String message =
"one or more of the features is read-only or is in a " +
"read-only entry - cannot continue";
new MessageDialog(null, message);
return;
}
}
else
{
final String message =
"Select a single contig to reverse and complement";
new MessageDialog(null, message);
return;
}
}
});
final JMenuItem delete_bases_item = new JMenuItem("Delete Selected Bases");
delete_bases_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
deleteSelectedBases();
final JMenuItem add_bases_item = new JMenuItem("Add Bases At Selection");
add_bases_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
addBases();
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
if(Options.getOptions().getPropertyTruthValue("val_mode"))
{
add(edit_feature_item);
add(edit_subsequence_item);
addSeparator();
add(edit_header_item);
addSeparator();
}
if(Options.getOptions().getUndoLevels() > 0)
{
add(undo_item);
addSeparator();
}
if(!Options.getOptions().getPropertyTruthValue("val_mode"))
{
add(edit_feature_item);
add(edit_subsequence_item);
addSeparator();
add(edit_header_item);
addSeparator();
}
add(add_qualifiers_item);
add(remove_qualifier_item);
add(duplicate_item);
add(merge_features_item);
add(unmerge_feature_item);
add(delete_features_item);
add(delete_segments_item);
add(delete_introns_item);
addSeparator();
add(move_features_menu);
add(copy_features_menu);
addSeparator();
add(trim_item);
add(trim_to_any_item);
add(trim_to_next_item);
add(trim_to_next_any_item);
add(extend_to_prev_stop_item);
add(extend_to_next_stop_item);
add(fix_stop_codons_item);
add(extend_to_next_stop_and_fix_item);
addSeparator();
add(auto_gene_name_item);
add(fix_gene_names_item);
add(reverse_complement_item);
add(reverse_complement_range_item);
add(delete_bases_item);
add(add_bases_item);
if(Options.readWritePossible())
{
final JMenuItem add_bases_from_file_item = new JMenuItem("Add Bases From File ...");
add_bases_from_file_item.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
addBasesFromFile();
add(add_bases_from_file_item);
if(owner instanceof FeatureDisplay)
{
add(new JSeparator());
add(contig_reordering);
}
}
/**
* Undo the last change by calling ActionController.undo().
* @param frame The Frame to use for MessageDialog components.
* @param selection The current Selection - needs to be cleared before undo
* @param entry_group Used to get the ActionController for calling
* ActionController.undo().
**/
private static void undo(final JFrame frame,
final Selection selection,
final EntryGroup entry_group)
{
// undo disabled
if(Options.getOptions().getUndoLevels() == 0)
// clear the selection because something in the selection might
// disappear after the undo() eg. create a feature, select it then undo
if(entry_group.getActionController().canUndo())
selection.clear();
if(!entry_group.getActionController().undo())
new MessageDialog(frame, "sorry - no further undo information");
}
/**
* Open an edit window (FeatureEdit) for each of the selected features.
* The edit component will listen for feature change events and update
* itself.
* @param frame The JFrame to use for MessageDialog components.
* @param selection The selected features to edit.
* @param entry_group Used to get the ActionController for calling
* startAction() and endAction().
**/
protected static void editSelectedFeatures(final JFrame frame,
final EntryGroup entry_group,
final Selection selection,
final GotoEventSource goto_event_source)
{
final int MAX_SELECTED_FEATURES = 25;
final FeatureVector features_to_edit = selection.getAllFeatures();
if(features_to_edit.size() > MAX_SELECTED_FEATURES)
new MessageDialog(frame, "warning: only editing the first " +
MAX_SELECTED_FEATURES + " selected features");
for(int i = 0; i < features_to_edit.size() && i < MAX_SELECTED_FEATURES;
++i)
{
final Feature selection_feature = features_to_edit.elementAt(i);
if(selection_feature.getEmblFeature() instanceof GFFStreamFeature &&
((GFFStreamFeature)selection_feature.getEmblFeature()).getChadoGene() != null)
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
{
new GeneBuilderFrame(selection_feature, entry_group,
selection, goto_event_source);
}
else
{
final JFrame edit_frame = new JFrame("Artemis Feature Edit: " +
selection_feature.getIDString() +
(selection_feature.isReadOnly() ?
" - (read only)" :
""));
final FeatureEdit fe = new FeatureEdit(selection_feature, entry_group,
selection, goto_event_source, edit_frame);
edit_frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
fe.stopListening();
edit_frame.dispose();
}
});
edit_frame.getContentPane().add(fe);
edit_frame.pack();
selection.set(features_to_edit);
}
/**
* Create a new EntryEdit component that contains only the selected
* sequence and the features in the selected range.
**/
private void editSubSequence()
{
if(getSelection().isEmpty())
new MessageDialog(getParentFrame(), "nothing selected");
final Range range = getSelection().getSelectionRange();
final EntryGroup new_entry_group = getEntryGroup().truncate(range);
new EntryEdit(new_entry_group).setVisible(true);
}
/**
* Open a EntryHeaderEdit window for the default entry.
**/
private void editHeader()
{
final Entry default_entry = getEntryGroup().getDefaultEntry();
if(default_entry == null)
{
final String message = "there is no default entry";
new MessageDialog(getParentFrame(), message);
}
else
{
if(default_entry.isReadOnly())
{
new MessageDialog(getParentFrame(),
"the default entry is read-only " +
"- cannot continue");
new EntryHeaderEdit(entry_group, default_entry);
}
}
/**
* Merge the selected features into one Feature. If there are selected
* segments then the owning Feature of each segment will be the Feature
* that is merged. This method will create a new Feature.
* @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 mergeFeatures(final JFrame frame,
final Selection selection,
final EntryGroup entry_group)
{
try
{
entry_group.getActionController().startAction();
if(!checkForSelectionFeatures(frame, selection, 10,
"really merge all (>10) " + "selected features?"))
final FeatureVector features_to_merge = selection.getAllFeatures();
if(features_to_merge.size() < 2)
{
new MessageDialog(frame,
"nothing to merge - select more than one feature");
final Feature merge_feature = features_to_merge.elementAt(0);
for(int i = 1; i < features_to_merge.size(); ++i)
{
final Feature this_feature = features_to_merge.elementAt(i);
if(this_feature.isForwardFeature() !=
merge_feature.isForwardFeature())
{
new MessageDialog(frame,
"all the features in a merge must be on the " +
"same strand");
if(!this_feature.getKey().equals(merge_feature.getKey()))
{
new MessageDialog(frame,
"all the features in a merge must have the " +
"same key");
if(Options.getOptions().isNoddyMode())
{
new YesNoDialog(frame, "Are you sure you want to merge the selected " +
"features?");
if(!dialog.getResult())
//
// GFF merge
if(merge_feature.getEmblFeature() instanceof GFFStreamFeature)
{
gffMergeFeatures(features_to_merge, merge_feature,
selection, entry_group);
return;
}
try
{
new_feature = merge_feature.duplicate();
}
catch(ReadOnlyException e)
{
final String message =
"one or more of the features is read-only or is in a " +
"read-only entry - cannot continue";
new MessageDialog(frame, message);
for(int i = 1; i < features_to_merge.size(); ++i)
{
final Feature this_feature = features_to_merge.elementAt(i);
final QualifierVector qualifiers = this_feature.getQualifiers();
for(int j = 0; j < qualifiers.size(); ++j)
{
final Qualifier this_qualifier = (Qualifier)qualifiers.elementAt(j);
try
{
new_feature.addQualifierValues(this_qualifier);
}
catch(EntryInformationException e)
{
try
{
new_feature.removeFromEntry();
}
catch(ReadOnlyException _)
{
// give up ...
}
final String message =
"destination entry does not support all the qualifiers " +
"needed by " + this_feature.getIDString();
new MessageDialog(frame, message);
}
catch(ReadOnlyException e)
{
final String message = "the new feature is read-only so " +
"some qualifiers have been lost";
new MessageDialog(frame, message);
final FeatureSegmentVector segments = this_feature.getSegments();
for(int j = 0; j < segments.size(); ++j)
{
segments.elementAt(j);
final Range this_range = this_segment.getRawRange();
try
{
new_feature.addSegment(this_range);
}
catch(ReadOnlyException e)
{
final String message =
"merging failed because the entry is read-only";