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.9 2005-12-09 16:17:13 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.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.QualifierInfo;
import uk.ac.sanger.artemis.io.QualifierInfoVector;
import uk.ac.sanger.artemis.io.QualifierVector;
import uk.ac.sanger.artemis.io.QualifierParseException;
import uk.ac.sanger.artemis.io.InvalidQualifierException;
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.*;
/**
* A menu with editing commands.
*
* @author Kim Rutherford
* @version $Id: EditMenu.java,v 1.9 2005-12-09 16:17:13 tjc Exp $
implements EntryGroupChangeListener, EntryChangeListener
{
/**
* 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, 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, 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, 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, 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, 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, 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, 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());
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
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();
JFrame frame = new JFrame("Contig Tool");
JScrollPane jsp = new JScrollPane();
ContigTool ct = new ContigTool(contig_features,
(FeatureDisplay)owner, jsp);
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.setVisible(true);
}
});
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 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 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 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();
if(owner instanceof FeatureDisplay)
add(contig_reordering);
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
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);
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);
}
}
/**
* 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);
new FeatureEdit(selection_feature, entry_group, selection,
goto_event_source).setVisible(true);
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())
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";
new MessageDialog(frame, message);
try
{
new_feature.removeFromEntry();
catch(ReadOnlyException _) {}
}
}
}
// this is set to true when a merge is done in the next (inner) loop
boolean keep_looping = true;
// this is a bit inefficient, but there aren't normally many segments
LOOP:
while(keep_looping)
{
new_feature.getSegments();
for(int i = 0; i < feature_segments.size() - 1; ++i)
{
feature_segments.elementAt(i);
final MarkerRange this_range = this_segment.getMarkerRange();
feature_segments.elementAt(i + 1);
final MarkerRange next_range = next_segment.getMarkerRange();
if(this_range.overlaps(next_range) &&
this_segment.getFrameID() == next_segment.getFrameID())
{
try
{
this_range.combineRanges(next_range, false).getRawRange();
new_feature.addSegment(new_range);
new_feature.removeSegment(this_segment);
new_feature.removeSegment(next_segment);
}
catch(ReadOnlyException e)
{
final String message =
"merging failed because the entry is read-only";
new MessageDialog(frame, message);
}
catch(LastSegmentException e)
{
throw new Error("internal error - tried to remove " +
"last segment: " + e);
if(Options.getOptions().isNoddyMode())
{
new YesNoDialog(frame, "delete old features?");
delete_old_features = delete_old_dialog.getResult();
}
else
if(delete_old_features)
{
if(getReadOnlyFeatures(features_to_merge).size() > 0)
new MessageDialog(frame, "deletion failed because the features " +
"are read-only");
else
{
for(int i = 0; i < features_to_merge.size(); ++i)
{
try
{
features_to_merge.elementAt(i).removeFromEntry();
}
catch(ReadOnlyException e)
{
new MessageDialog(frame, "deletion failed one or more of the " +
"features are read-only");
selection.set(new_feature);
}
finally
{
entry_group.getActionController().endAction();
}
}
/**
* If the selection contains exactly two segments and those segments are
* adjacent in the same feature, split the feature into two pieces. The
* orignal feature is truncated and a new feature is created. The
* qualifiers of the old feature are copied to new feature.
* @param frame The JFrame to use for MessageDialog components.