Newer
Older
/* FeatureDisplay.java
*
* created: Fri Oct 9 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/FeatureDisplay.java,v 1.66 2009-06-12 13:50:35 tjc Exp $
import uk.ac.sanger.artemis.util.DatabaseDocument;
import uk.ac.sanger.artemis.util.ReadOnlyException;
import uk.ac.sanger.artemis.util.FileDocument;
import uk.ac.sanger.artemis.util.OutOfRangeException;
import uk.ac.sanger.artemis.util.StringVector;
import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
import uk.ac.sanger.artemis.io.GFFUtils;
import uk.ac.sanger.artemis.io.InvalidRelationException;
import uk.ac.sanger.artemis.io.Qualifier;
import uk.ac.sanger.artemis.io.EntryInformation;
import uk.ac.sanger.artemis.io.SimpleEntryInformation;
import uk.ac.sanger.artemis.io.RawStreamSequence;
import uk.ac.sanger.artemis.io.FastaStreamSequence;
import uk.ac.sanger.artemis.io.Sequence;
import uk.ac.sanger.artemis.io.Location;
import uk.ac.sanger.artemis.*;
import uk.ac.sanger.artemis.sequence.*;
import java.awt.event.*;
import java.awt.*;
import java.lang.Math;
import java.util.Vector;
import java.util.Comparator;
import javax.swing.border.Border;
import javax.swing.border.BevelBorder;
import javax.swing.JOptionPane;
/**
* This component is used for displaying an Entry.
*
* @author Kim Rutherford
* @version $Id: FeatureDisplay.java,v 1.66 2009-06-12 13:50:35 tjc Exp $
**/
public class FeatureDisplay extends EntryGroupPanel
implements EntryGroupChangeListener,
EntryChangeListener, FeatureChangeListener,
SelectionChangeListener, GotoListener, SequenceChangeListener,
DisplayComponent, OptionChangeListener, DisplayAdjustmentListener,
DragGestureListener, DropTargetListener,
DragSourceListener
private final static int ZOOM_TO_SELECTION_KEY = KeyEvent.VK_Z;
private final static int ARROW_LEFT = KeyEvent.VK_LEFT;
private final static int ARROW_RIGHT = KeyEvent.VK_RIGHT;
protected final static int SCROLLBAR_AT_TOP = 1;
protected final static int SCROLLBAR_AT_BOTTOM = 2;
private final static int FORWARD = Bases.FORWARD;
private final static int REVERSE = Bases.REVERSE;
private final static int NO_FRAME = FeatureSegment.NO_FRAME;
private final static int FORWARD_STRAND = FeatureSegment.FORWARD_STRAND;
private final static int REVERSE_STRAND = FeatureSegment.REVERSE_STRAND;
private final static int FORWARD_FRAME_1 = FeatureSegment.FORWARD_FRAME_1;
private final static int FORWARD_FRAME_2 = FeatureSegment.FORWARD_FRAME_2;
private final static int FORWARD_FRAME_3 = FeatureSegment.FORWARD_FRAME_3;
private final static int REVERSE_FRAME_3 = FeatureSegment.REVERSE_FRAME_3;
private final static int REVERSE_FRAME_2 = FeatureSegment.REVERSE_FRAME_2;
private final static int REVERSE_FRAME_1 = FeatureSegment.REVERSE_FRAME_1;
private final static int SCALE_LINE = FeatureSegment.SCALE_LINE;
/**
* The JScrollBar for this FeatureDisplay object. We create the scrollbar
* as part of this object rather than in the EntryEdit component because we
* may need to change the parameters of the scrollbar later.
**/
private JScrollBar scrollbar = null;
/** A scroll bar for changing the viewing scale. */
private ZoomScrollBar scale_changer = null;
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/** Used to colour the frames. */
private Color light_grey = new Color(240, 240, 240);
/** Used to colour sequence line. */
private Color not_so_light_grey = new Color(200, 200, 200);
/**
* The colour used for the active entry line when
* one_line_per_entry is set.
**/
private Color active_entry_colour = new Color(255, 255, 140);
/**
* This Vector containing the references of those features that are
* currently visible.
**/
private FeatureVector visible_features = new FeatureVector();
/**
* If true updateVisibleFeatureVector() will be called by paint().
* updateVisibleFeatureVector() sets this to false,
* needVisibleFeatureVectorUpdate() sets this to true.
**/
private boolean update_visible_features = true;
/** Contains those objects listening for adjustment events. */
final private Vector<DisplayAdjustmentListener> adjustment_listener_list =
new Vector<DisplayAdjustmentListener>();
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/**
* The index of the first base that we are displaying.
* Can be negative if hard_left_edge is true.
**/
private int left_edge_base = 1;
/** See getScaleFactor(). */
private int scale_factor = 3;
/** See getScaleFactor(). */
private float scale_value = 1;
/** true if labels should be shown. */
private boolean show_labels = true;
/**
* This variable is true if the forward frame lines(or forward entry lines
* - see one_line_per_entry) should be drawn.
**/
private boolean show_forward_lines = true;
/**
* This variable is true if the reverse frame lines(or reverse entry lines
* - see one_line_per_entry) should be drawn.
**/
private boolean show_reverse_lines = true;
/**
* If true draw all features, sequence and scale lines reverse complemented.
**/
private boolean rev_comp_display = false;
/**
* This variable is true if(for each strand) each entry should be on a
* separate line.
**/
private boolean one_line_per_entry = false;
private boolean feature_stack_view = false;
private short MAX_LINES_FEATURE_STACK = 10;
/** expand / collapse stack view, 2 or 1 respectively */
private int STACK_EXPAND_FACTOR = 1;
/** visible features sorted by size */
private FeatureVector visibleFeaturesSortBySize;
/** visible features sorted by position */
private FeatureVector visibleFeaturesSortByPosition;
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
/**
* If true the there will never be a gap between the left edge of the
* screen and the first visible base.
**/
private boolean hard_left_edge = true;
/** true if source features should be shown. */
private boolean show_source_features = false;
/** true if stop codons should be shown. */
private boolean show_stop_codons = true;
/** true if start codons should be shown. */
private boolean show_start_codons = false;
/** true if directional arrows should be shown on features. */
private boolean show_feature_arrows;
/** true a black border will be drawn around each feature. */
private boolean show_feature_borders;
/**
* This variable is true if each base should be drawn in a different colour
* at scale feature 1.
**/
private boolean show_base_colours = false;
/**
* All features(not just CDS features) will be drawn on the frame lines if
* and only if this variable is true. See setFrameFeaturesFlag() and
* getFrameFeaturesFlag().
**/
private boolean frame_features_flag = false;
/**
* The position(s) of the last mouse click on the dna line. The
* MarkerRange contains a reference to the appropriate Strand and contains
* the base positions. See getMarkerRangeFromPosition() to understand why
* one click can give multiple bases.
**/
private MarkerRange click_range = null;
/**
* The last(FeatureSegment) Marker that the user clicked on. This is used
* for dragging the ends of segments.
**/
private Marker click_segment_marker = null;
/**
* This is true if click_segment_marker is the Marker at the start of
* segment false otherwise. The value is only useful if
* click_segment_marker is set.
**/
private boolean click_segment_marker_is_start_marker = false;
/**
* When a FeatureSegment Marker drag starts, this is set to the Marker at
* the other end of the segment. This is used to check that the drag has
* not move the Marker too far(past the end of the segment).
**/
private Marker other_end_of_segment_marker = null;
/**
* Features with a /score qualifier less than this value will not be shown.
**/
private int current_min_score = 0;
/**
* Features with a /score qualifier greater than this value will not be
* shown.
**/
private int current_max_score = 100;
private MouseEvent last_mouse_press_event;
/**
* If set no DisplayAdjustment events will be sent. This is set by
* displayAdjustmentValueChanged() to prevent an event we send from
* returning to us(a FeatureDisplay can listen for DisplayAdjustment
* events from another FeatureDisplay).
**/
private boolean disable_display_events = false;
/**
* Set to true by selectionChanged() to tell updateVisibleFeatureVector()
* to raise the contents of the select before updating.
**/
private boolean raise_selection_flag = false;
/** the minimum distance in pixels between the labels. */
private final static int MINIMUM_LABEL_SPACING = 80;
/** colour used for A. */
private static Color dark_green = new Color(0, 150, 0);
private static Vector<String> contigKeys;
private static Vector<String> allPossibleContigKeys;
private Object[] protein_keys = { "CDS",
"BLASTCDS",
"polypeptide",
"pseudogenic_exon"};
/**
* Create a new FeatureDisplay object with the horizontal scrollbar at the
* bottom of the component.
* @param entry_group The EntryGroup that this component will display.
* @param selection The Selection object for this component. Selected
* objects will be highlighted.
* @param goto_event_source The object to use when we need to call
* gotoBase().
* @param base_plot_group The BasePlotGroup associated with this JMenu -
* needed to call getCodonUsageAlgorithm()
**/
public FeatureDisplay(final EntryGroup entry_group,
final Selection selection,
final GotoEventSource goto_event_source,
final BasePlotGroup base_plot_group)
{
this(entry_group, selection, goto_event_source,
}
/**
* Create a new FeatureDisplay object.
* @param entry_group The EntryGroup that this component will display.
* @param owning_component The EntryEdit object that contains the selection
* that this component uses.
* @param scrollbar_at_top If true the horizontal scrollbar will be at the
* top of component.
* @param base_plot_group The BasePlotGroup associated with this JMenu -
* needed to call getCodonUsageAlgorithm()
* @param scrollbar_style Controls the type of horizontal scrollbar. Must
* be one of SCROLLBAR_AT_TOP, SCROLLBAR_AT_BOTTOM or NO_SCROLLBAR.
**/
public FeatureDisplay(final EntryGroup entry_group,
final Selection selection,
final GotoEventSource goto_event_source,
final BasePlotGroup base_plot_group,
final int scrollbar_style)
{
super(entry_group, selection, goto_event_source, base_plot_group);
show_feature_arrows =
Options.getOptions().getPropertyTruthValue("draw_feature_arrows");
show_feature_borders =
Options.getOptions().getPropertyTruthValue("draw_feature_borders");
frame_features_flag =
Options.getOptions().getPropertyTruthValue("features_on_frame_lines");
one_line_per_entry =
Options.getOptions().getPropertyTruthValue("one_line_per_entry");
feature_stack_view =
Options.getOptions().getPropertyTruthValue("feature_stack_view");
show_labels =
Options.getOptions().getPropertyTruthValue("feature_labels");
show_reverse_lines =
Options.getOptions().getPropertyTruthValue("show_reverse_lines");
show_forward_lines =
Options.getOptions().getPropertyTruthValue("show_forward_lines");
final StringVector frame_line_features =
Options.getOptions().getOptionValues("frame_line_features");
if(frame_line_features != null)
protein_keys = frame_line_features.toArray();
addComponentListener(new ComponentAdapter()
{
public void componentResized(ComponentEvent e)
{
// update the scroll bar as soon as we know the size of the canvas
fixScrollbar();
needVisibleFeatureVectorUpdate();
fireAdjustmentEvent(DisplayAdjustmentEvent.ALL_CHANGE_ADJUST_EVENT);
}
public void componentShown(ComponentEvent e)
{
// update the scroll bar as soon as we know the size of the canvas
fixScrollbar();
needVisibleFeatureVectorUpdate();
fireAdjustmentEvent(DisplayAdjustmentEvent.ALL_CHANGE_ADJUST_EVENT);
}
});
setScaleValue();
if(scrollbar_style == SCROLLBAR_AT_TOP)
createScrollbar(true);
else if(scrollbar_style == SCROLLBAR_AT_BOTTOM)
createScrollbar(false);
createScaleScrollbar();
addListeners();
needVisibleFeatureVectorUpdate();
getSelection().addSelectionChangeListener(this);
getGotoEventSource().addGotoListener(this);
getEntryGroup().addEntryGroupChangeListener(this);
getEntryGroup().addEntryChangeListener(this);
getEntryGroup().addFeatureChangeListener(this);
getBases().addSequenceChangeListener(this, Bases.MIN_PRIORITY);
Options.getOptions().addOptionChangeListener(this);
DragSource dragSource = DragSource.getDefaultDragSource();
dragSource.createDefaultDragGestureRecognizer(
this, // component where drag originates
DnDConstants.ACTION_COPY_OR_MOVE, // actions
this); // drag gesture recognizer
setDropTarget(new DropTarget(this,this));
}
/**
* Overriden to call fixCanvasSize()
**/
public void setVisible(final boolean visible)
{
super.setVisible(visible);
fixCanvasSize();
}
/**
* Set value of the show label flag.
* @param show_label Show labels if and only if this argument is true.
**/
{
if(this.show_labels != show_labels)
{
this.show_labels = show_labels;
fixCanvasSize();
}
}
/**
* Get the value of the "show label" flag.
**/
{
return show_labels;
}
/**
* Set value of the "show forward frame lines" flag.
* @param show_forward_lines Show forward frame lines if and only if
* this argument is true.
**/
{
if(this.show_forward_lines != show_forward_lines)
{
this.show_forward_lines = show_forward_lines;
fixCanvasSize();
}
}
/**
* Get the value of the "show forward frame lines" flag.
**/
{
return show_forward_lines;
}
/**
* Set value of the "show reverse frame lines" flag.
* @param show_reverse_lines Show frame lines if and only if this
* argument is true.
**/
{
if(this.show_reverse_lines != show_reverse_lines)
{
this.show_reverse_lines = show_reverse_lines;
fixCanvasSize();
}
}
/**
* Get the value of the "show source features" flag.
**/
{
return show_source_features;
}
/**
* Set value of the "show source features" flag.
* @param show_source_features Show features with a "source" key if and
* only if this argument is true.
**/
{
if(this.show_source_features != show_source_features)
{
this.show_source_features = show_source_features;
needVisibleFeatureVectorUpdate();
}
}
/**
* Get the value of the "show frame lines" flag.
**/
{
return show_reverse_lines;
}
/**
* Set value of the show base colours flag.
* @param show_base_colours At scale_factor less than two show each base in
* a different colour if and only if this argument is true.
**/
{
if(this.show_base_colours != show_base_colours)
{
this.show_base_colours = show_base_colours;
if(getScaleFactor() > 1)
setScaleFactor(1);
repaint();
}
}
/**
* Get the value of the "show base colours" flag.
**/
{
return show_base_colours;
}
/**
* Set value of the "one line per entry" flag.
* @param one_line_per_entry If true then each entry will be shown on a
* different line, instead of showing frame lines.
**/
{
if(this.one_line_per_entry != one_line_per_entry)
{
this.one_line_per_entry = one_line_per_entry;
fixCanvasSize();
}
}
/**
* Get the value of the "one line per entry" flag.
**/
/**
* Set value of the feature stack view flag.
* @param feature_stack_view If true then each CDS will be shown on a
* different line, instead of showing frame lines.
**/
protected void setFeatureStackViewFlag(final boolean feature_stack_view)
{
if(this.feature_stack_view != feature_stack_view)
{
this.feature_stack_view = feature_stack_view;
fixCanvasSize();
}
}
/**
* Get the value of the "one line per entry" flag.
**/
protected boolean getFeatureStackViewFlag()
{
return feature_stack_view;
}
/**
* Set value of the "hard left edge" flag.
* @param hard_left_edge If true the there will never be a gap between the
* left edge of the screen and the first visible base. If false base one
* can be moved to the centre of the display.
**/
{
if(this.hard_left_edge != hard_left_edge)
{
this.hard_left_edge = hard_left_edge;
if(hard_left_edge && getForwardBaseAtLeftEdge() < 1)
setFirstVisibleForwardBase(1);
fixScrollbar();
}
}
/**
* Set value of the show stop codons flag.
* @param show_stop_codons Show stop codons if and only if this argument is
* true.
**/
{
if(this.show_stop_codons != show_stop_codons)
{
this.show_stop_codons = show_stop_codons;
}
}
/**
* Return the value of the "show stop codons" flag.
**/
return show_stop_codons;
}
/**
* Set value of the show start codons flag.
* @param show_start_codons Show start codons if and only if this argument
* is true.
**/
{
if(this.show_start_codons != show_start_codons)
{
this.show_start_codons = show_start_codons;
}
}
/**
* Return the value of the "show start codons" flag.
**/
{
return show_start_codons;
}
/**
* Set value of the reverse complement display flag.
* @param show_start_codons Draw all features and sequence reverse
* complemented if and only if this argument is true.
**/
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
{
if(this.rev_comp_display != rev_comp_display)
{
this.rev_comp_display = rev_comp_display;
int remember_position = getCentreForwardBase();
// we want to keep the selection visible after the flip, so
// that will override the centre position
final Marker first_base_marker =
getSelection().getStartBaseOfSelection();
if(first_base_marker != null && baseVisible(first_base_marker))
remember_position = first_base_marker.getRawPosition();
final Marker last_base_marker =
getSelection().getStartBaseOfSelection();
if(last_base_marker != null && baseVisible(last_base_marker))
remember_position = last_base_marker.getRawPosition();
fireAdjustmentEvent(DisplayAdjustmentEvent.REV_COMP_EVENT);
makeBaseVisibleInternal(remember_position, isRevCompDisplay(), true);
needVisibleFeatureVectorUpdate();
fixScrollbar();
}
}
/**
* Return the value of the "reverse complement display" flag.
**/
{
return rev_comp_display;
}
/**
* Set value of the show feature arrows flag.
* @param show_feature_arrows Show directional arrows if and only if this
* argument is true.
**/
{
if(this.show_feature_arrows != show_feature_arrows)
{
this.show_feature_arrows = show_feature_arrows;
}
}
/**
* Return the value of the "show feature arrows" flag.
**/
{
return show_feature_arrows;
}
/**
* Set value of the show feature borders flag.
* @param show_feature_borders Draw a border around each feature if and
* only if this argument is true.
**/
{
if(this.show_feature_borders != show_feature_borders)
{
this.show_feature_borders = show_feature_borders;
}
}
/**
* Return the value of the "show feature borders" flag.
**/
{
return show_feature_borders;
}
/**
* Set value of the show frame features flag.
* @param frame_features_flag All features(not just CDS features) will be
* drawn on the frame lines if and only if this argument is true.
**/
{
if(this.frame_features_flag != frame_features_flag)
{
this.frame_features_flag = frame_features_flag;
}
}
/**
* Return the value of the "show frame features" flag.
**/
{
return frame_features_flag;
}
/**
* Set the value of the minimum score for this FeatureDisplay - features
* that have a /score lower than this value are never shown.
**/
{
current_min_score = minimum_score;
needVisibleFeatureVectorUpdate();
}
/**
* Return the value of the minimum score for this FeatureDisplay - see
* setMinimumScore().
**/
{
return current_min_score;
}
/**
* Set the value of the maximum score for this FeatureDisplay - features
* that have a /score higher than this value are never shown.
**/
{
current_max_score = maximum_score;
needVisibleFeatureVectorUpdate();
}
/**
* Return the value of the maximum score for this FeatureDisplay - see
* setMaximumScore().
**/
{
return current_max_score;
}
/**
* Adds the specified event adjustment listener to receive adjustment
* change events from this object.
* @param l the event change listener.
**/
public void addDisplayAdjustmentListener(DisplayAdjustmentListener l)
{
adjustment_listener_list.addElement(l);
}
/**
* Removes the specified event listener so that it no longer receives
* adjustment change events from this object.
* @param l the event change listener.
**/
public void removeDisplayAdjustmentListener(DisplayAdjustmentListener l)
{
adjustment_listener_list.removeElement(l);
}
/**
* Handle key press events. This is static because making it non-static
* triggered a java.lang.VerifyError
**/
private static void handleKeyPress(final FeatureDisplay feature_display,
final KeyEvent event)
{
// this is done so that menu shortcuts don't cause each action to be
// performed twice
if(event.getModifiers() != 0)
return;
switch(event.getKeyCode())
{
case ZOOM_TO_SELECTION_KEY:
FeaturePopup.zoomToSelection(feature_display);
break;
case ARROW_LEFT:
feature_display.setFirstBase(
feature_display.getFirstVisibleForwardBase()-
feature_display.scrollbar.getUnitIncrement());
break;
case ARROW_RIGHT:
feature_display.setFirstBase(
feature_display.getFirstVisibleForwardBase()+
feature_display.scrollbar.getUnitIncrement());
break;
default:
break;
}
}
/**
* Set the scale factor and update the display if the scale factor has
* changed. A factor of zero means the full translation will be visible.
* At higher scale factors only stop codons are visible, and a bigger
* number will mean more bases are visible.
**/
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
{
if(this.scale_factor != scale_factor)
{
// we will try to keep the base in the centre of the view to stay where
// it is, so we save it's position in remember_position.
int remember_position = getCentreForwardBase();
// if the first base is visible then keep it visible
if(hard_left_edge && getFirstVisibleForwardBase() == 1)
remember_position = 1;
if(!getSelection().isEmpty())
{
// but, we want to keep the selection visible after a scale change, so
// that will override the centre position
final Marker first_base_marker =
getSelection().getStartBaseOfSelection();
final int first_base_marker_raw_position =
first_base_marker.getRawPosition();
final int first_base_marker_position;
if(isRevCompDisplay())
first_base_marker_position =
getBases().getComplementPosition(first_base_marker_raw_position);
else
first_base_marker_position = first_base_marker_raw_position;
final Marker last_base_marker =
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
final int last_base_marker_raw_position =
last_base_marker.getRawPosition();
final int last_base_marker_position;
if(isRevCompDisplay())
last_base_marker_position =
getBases().getComplementPosition(last_base_marker_raw_position);
else
last_base_marker_position = last_base_marker_raw_position;
final int lowest_visible_base = getFirstVisibleForwardBase();
final int highest_visible_base = getLastVisibleForwardBase();
// first selected base or first visible base, whichever is greater
int restricted_first_selected_base = lowest_visible_base;
// last selected base or last visible base, whichever is smaller
int restricted_last_selected_base = highest_visible_base;
if(first_base_marker != null)
{
if(first_base_marker_position > lowest_visible_base &&
first_base_marker_position < highest_visible_base)
restricted_first_selected_base = first_base_marker_position;
}
if(last_base_marker != null)
{
if(last_base_marker_position < highest_visible_base &&
last_base_marker_position > lowest_visible_base)
restricted_last_selected_base = last_base_marker_position;
}
if(getSelection().getMarkerRange() == null)
remember_position = restricted_first_selected_base;
else
{
// keep the centre of the selection in the middle of the display if
// a range of bases is selected
remember_position = restricted_first_selected_base +
(restricted_last_selected_base -
restricted_first_selected_base) / 2;
}
}
this.scale_factor = scale_factor;
setScaleValue();
if(scale_changer != null)
scale_changer.setValue(scale_factor);
setCentreVisibleForwardBase(remember_position);
fixScrollbar();
fireAdjustmentEvent(DisplayAdjustmentEvent.SCALE_ADJUST_EVENT);
needVisibleFeatureVectorUpdate();
}
}
/**
* Implementation of the FeatureChangeListener interface. We listen to
* FeatureChange events so that we can update the display if qualifiers
* change.
**/
public void featureChanged(final FeatureChangeEvent event)
{
final Feature event_feature = event.getFeature();
if( event.getType() == FeatureChangeEvent.LOCATION_CHANGED &&
event_feature.getEmblFeature() instanceof GFFStreamFeature &&
!GeneUtils.isDatabaseEntry(event_feature.getEmblFeature()))
{
try
{
GFFUtils.updateSegmentRangeStore((GFFStreamFeature)event_feature.getEmblFeature(),
event.getOldLocation(), event.getNewLocation());
// the feature isn't in an active entry
if(!getEntryGroup().contains(event_feature))
return;
// if the feature is visible now or is in the list of visible features
//(ie. it was visible previously) then redisplay.
if(featureVisible(event_feature) ||
getVisibleFeatures().contains(event_feature))
{
// update the visible_features vector
if(getVisibleFeatures().contains(event_feature) &&
!featureVisible(event_feature))
getVisibleFeatures().remove(event_feature);
else
{