Newer
Older
/* FeatureEdit.java
*
* created: Tue Dec 1 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/FeatureEdit.java,v 1.61 2008-08-01 12:46:56 tjc Exp $
**/
package uk.ac.sanger.artemis.components;
import uk.ac.sanger.artemis.util.*;
import uk.ac.sanger.artemis.*;
import uk.ac.sanger.artemis.io.GFFDocumentEntry;
import uk.ac.sanger.artemis.io.OutOfDateException;
import uk.ac.sanger.artemis.io.LocationParseException;
import uk.ac.sanger.artemis.io.QualifierParseException;
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.KeyVector;
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.EntryInformation;
import uk.ac.sanger.artemis.io.EntryInformationException;
import uk.ac.sanger.artemis.io.StreamQualifier;
import uk.ac.sanger.artemis.io.QualifierInfo;
import uk.ac.sanger.artemis.components.genebuilder.GeneBuilderFrame;
import uk.ac.sanger.artemis.components.genebuilder.GeneEditorPanel;
import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
import uk.ac.sanger.artemis.components.genebuilder.ProteinMapPanel;
import uk.ac.sanger.artemis.components.genebuilder.cv.CVPanel;
import uk.ac.sanger.artemis.components.genebuilder.gff.PropertiesPanel;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Date;
import java.util.Hashtable;
import java.util.Collections;
import java.util.Comparator;
* @version $Id: FeatureEdit.java,v 1.61 2008-08-01 12:46:56 tjc Exp $
implements EntryChangeListener, FeatureChangeListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
/** The choice of feature keys - created in createComponents(). */
private KeyChoice key_choice;
/** The choice of qualifiers - created in createComponents(). */
private QualifierChoice qualifier_choice = null;
private final static int LOCATION_TEXT_WIDTH = 80;
/** The location text - set by updateLocation(). */
/** When pressed - apply changes and dispose of the component. */
/** When pressed - discard changes and dispose of the component. */
/** When pressed - apply changes and keep the component open. */
/** Edit area for qualifiers - created by createComponents(). */
private QualifierTextArea qualifier_text_area;
/** The Feature this object is displaying. */
private Feature edit_feature;
/**
* The GotoEventSource that was passed to the constructor - used for the
* "Goto Feature" button.
**/
private GotoEventSource goto_event_source;
/** Entry containing the Feature this object is displaying. */
private Entry edit_entry;
/** EntryGroup that contains this Feature (passed to the constructor). */
private EntryGroup entry_group;
/**
* called or null if this is not a RWCorbaFeature.
**/
private Date datestamp = null;
/** The Selection that was passed to the constructor. */
private Selection selection;
/**
* The contents of the QualifierTextArea before the user edits anything.
* This is used to work out if anything has changed since the creation of
* the FeatureEdit.
**/
final String orig_qualifier_text;
private EntryInformation entry_information;
/**
* Create a new FeatureEdit object from the given Feature.
* @param entry_group The EntryGroup that contains this Feature.
* @param selection The Selection operate on. The operations are "Remove
* Range" and "Grab Range"
public FeatureEdit(final Feature edit_feature,
final EntryGroup entry_group,
final Selection selection,
final GotoEventSource goto_event_source,
final JFrame frame)
this(edit_feature, entry_group, selection,
goto_event_source, frame,
edit_feature.getEntry().getEntryInformation());
}
public FeatureEdit(final Feature edit_feature,
final EntryGroup entry_group,
final Selection selection,
final GotoEventSource goto_event_source,
final JFrame frame, final EntryInformation entry_information)
{
this.entry_information = entry_information;
this.entry_group = entry_group;
this.selection = selection;
orig_qualifier_text = qualifier_text_area.getText();
edit_feature.getEntry().addEntryChangeListener(this);
edit_feature.addFeatureChangeListener(this);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent event)
{
stopListening();
frame.dispose();
}
});
}
private boolean isPartialSequence()
{
return edit_feature.getEmblFeature().getEntry().getSequence() instanceof PartialSequence;
}
/**
* Set the feature to edit
* @param edit_feature
* @param isSet
*/
public void setActiveFeature(final Feature edit_feature,
final boolean isSet)
this.edit_feature = edit_feature;
this.edit_entry = edit_feature.getEntry();
updateFromFeature();
}
/**
* Remove this object as a feature and entry change listener.
**/
getEntry().removeEntryChangeListener(this);
getFeature().removeFeatureChangeListener(this);
if(cvForm != null)
getFeature().removeFeatureChangeListener(cvForm);
if(propertiesPanel != null)
getFeature().removeFeatureChangeListener(propertiesPanel);
if(matchForm != null)
getFeature().removeFeatureChangeListener(matchForm);
}
/**
* Implementation of the EntryChangeListener interface. We listen to
* EntryChange events so we can notify the user if of this component if the
* feature gets deleted.
**/
{
switch(event.getType())
{
case EntryChangeEvent.FEATURE_DELETED:
}
break;
default:
// do nothing;
break;
}
}
/**
* Add an ActionListener to the Cancel JButton of this FeatureEdit.
**/
public void addCancelActionListener(final ActionListener l)
{
cancel_button.addActionListener(l);
}
/**
* Remove an ActionListener from the Cancel JButton of this FeatureEdit.
**/
public void removeCancelActionListener(final ActionListener l)
{
cancel_button.removeActionListener(l);
}
/**
* Add an ActionListener to the Apply JButton of this FeatureEdit.
**/
public void addApplyActionListener(final ActionListener l)
{
}
/**
* Remove an ActionListener from the Apply JButton of this FeatureEdit.
**/
public void removeApplyActionListener(final ActionListener l)
{
apply_button.removeActionListener(l);
}
/**
* Implementation of the FeatureChangeListener interface. We need to
* listen to feature change events from the Features in this object so that
* we can update the display.
* @param event The change event.
**/
public void featureChanged(FeatureChangeEvent event)
{
case FeatureChangeEvent.LOCATION_CHANGED:
updateLocation();
break;
case FeatureChangeEvent.SEGMENT_CHANGED:
updateLocation();
break;
case FeatureChangeEvent.KEY_CHANGED:
updateKey();
break;
case FeatureChangeEvent.QUALIFIER_CHANGED:
if(qualifier_text_area.getText().equals(orig_qualifier_text))
updateFromFeature();
else
{
if(!event.getFeature().getIDString().equals(getFeature().getIDString()))
break;
final String message =
"warning: the qualifiers have changed outside the editor - " +
"view now?";
if(yes_no_dialog.getResult())
new FeatureViewer(getFeature());
}
break;
default:
updateFromFeature();
break;
}
}
/**
* Create all the components for this FeatureEdit component.
**/
//qualifier_text_area.setWrapStyleWord(true);
FlowLayout flowLayoutZeroHgap = new FlowLayout(FlowLayout.LEADING);
flowLayoutZeroHgap.setHgap(0);
new KeyChoice(getEntryInformation(),getFeature().getKey());
final JPanel key_and_qualifier_panel = new JPanel();
location_text.setBackground(Color.white);
final JPanel key_panel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
final JLabel locLabel = new JLabel("Location: ");
final JLabel keyLabel = new JLabel("Key: ");
keyLabel.setHorizontalAlignment(SwingConstants.RIGHT);
keyLabel.setPreferredSize(locLabel.getPreferredSize());
key_panel.add(keyLabel);
key_and_qualifier_panel.setLayout(new BorderLayout());
key_and_qualifier_panel.add(key_panel, "West");
boolean isGFF = false;
if(edit_feature.getEmblFeature().getEntry() instanceof GFFDocumentEntry)
isGFF = true;
qualifier_choice = new QualifierChoice(getEntryInformation(),
key_choice.getSelectedItem(),null,
isGFF);
final JPanel qualifier_panel = new JPanel(new FlowLayout(FlowLayout.TRAILING,0,0));
final JButton qualifier_add_button = new JButton("Add Qualifier:");
qualifier_panel.add(qualifier_add_button);
qualifier_panel.add(qualifier_choice);
key_and_qualifier_panel.add(qualifier_panel, "East");
key_choice.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent _)
{
qualifier_add_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
getEntryInformation().getQualifierInfo(qualifier_name);
if(qualifier_info == null)
qualifier_info = new QualifierInfo(qualifier_name,
QualifierInfo.OPTIONAL_QUOTED_TEXT,
null, null, false);
qualifier_text_area.append("/" + qualifier_name);
{
case QualifierInfo.QUOTED_TEXT:
if(qualifier_name.equals("GO"))
{
// special case for /GO
final java.util.Calendar calendar =
java.util.Calendar.getInstance();
final java.text.SimpleDateFormat date_format =
new java.text.SimpleDateFormat("yyyyMMdd");
final StringBuffer result_buffer = new StringBuffer();
date_format.format(current_time, result_buffer,
new java.text.FieldPosition(java.text.DateFormat.DATE_FIELD));
final String go_string = "aspect=; term=; GOid=GO:; "+
"evidence=ISS; db_xref=GOC:unpublished; " +
qualifier_text_area.append("=\"" + go_string + "\"");
}
else if(qualifier_name.equals("controlled_curation"))
{
final java.util.Calendar calendar =
java.util.Calendar.getInstance();
final Date current_time = calendar.getTime();
final java.text.SimpleDateFormat date_format =
new java.text.SimpleDateFormat("yyyyMMdd");
final StringBuffer result_buffer = new StringBuffer();
date_format.format(current_time, result_buffer,
new java.text.FieldPosition(java.text.DateFormat.DATE_FIELD));
final String cc_string = "term=; db_xref=; date="+ result_buffer;
qualifier_text_area.append("=\"" + cc_string + "\"");
}
else
qualifier_text_area.append ("=\"\"");
break;
case QualifierInfo.NO_VALUE:
case QualifierInfo.OPTIONAL_QUOTED_TEXT:
break;
//final JPanel outer_location_button_panel = new JPanel(flowLayoutZeroHgap);
//outer_location_button_panel.setLayout(new BorderLayout(0,0));
final JPanel location_button_panel = new JPanel(flowLayoutZeroHgap);
//outer_location_button_panel.add(location_button_panel, "West");
lower_panel.add(location_button_panel, "North");
final JPanel location_panel = new JPanel(new BorderLayout(0,0));
location_panel.add(locLabel, "West");
final JButton complement_button = new JButton("Complement");
location_button_panel.add(complement_button);
complement_button.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
complementLocation();
{
final JButton refresh_button = new JButton("Refresh");
location_button_panel.add(refresh_button);
refresh_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
refresh();
}
});
}
final JButton grab_button = new JButton("Grab Range");
location_button_panel.add(grab_button);
grab_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final JButton remove_button = new JButton("Remove Range");
location_button_panel.add(remove_button);
remove_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
removeSelectedRange();
final JButton goto_button = new JButton("Goto Feature");
location_button_panel.add(goto_button);
{
public void actionPerformed(ActionEvent e)
{
goto_event_source.gotoBase(getFeature().getFirstBaseMarker());
final JButton select_button = new JButton("Select Feature");
location_button_panel.add(select_button);
select_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
getSelection().set(getFeature());
final JButton tidy_button = new JButton("Tidy");
location_button_panel.add(tidy_button);
tidy_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
{
final String error_string = exception.getMessage();
"Cannot tidy - qualifier error: " +
error_string);
/*if(Options.getOptions().getProperty("external_editor") != null)
{
final JButton external_fasta_edit_button = new JButton("MESS/FASTA");
location_button_panel.add(external_fasta_edit_button);
external_fasta_edit_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
if(getFeature().getQualifierByName("fasta_file") != null)
{
final String DEFAULT_MAX_EUK_FASTA_HITS = "10";
final String max_fasta_hits;
final String max_fasta_hits_from_options =
Options.getOptions().getProperty("mess_fasta_hits");
if(Options.getOptions().isEukaryoticMode())
{
if (max_fasta_hits_from_options == null)
externalEdit(new String[] { "-fasta", "-maxhits",
max_fasta_hits, "-euk" });
}
else
{
if(max_fasta_hits_from_options == null)
{
externalEdit(new String[] { "-fasta", "-maxhits",
max_fasta_hits_from_options });
final JButton external_blastp_edit_button = new JButton("MESS/BLASTP");
location_button_panel.add(external_blastp_edit_button);
external_blastp_edit_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
if(getFeature().getQualifierByName("blastp_file") != null)
{
final String DEFAULT_MAX_BLASTP_HITS = "10";
final String max_blastp_hits;
final String max_blastp_hits_from_options =
Options.getOptions().getProperty("mess_blastp_hits");
externalEdit(new String[] { "-blastp", "-maxhits",
max_blastp_hits, "-euk" });
externalEdit(new String[] { "-blastp", "-maxhits",
max_blastp_hits });
final JButton external_go_edit_button = new JButton("MESS/GO");
location_button_panel.add(external_go_edit_button);
external_go_edit_button.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
try
{
if(getFeature().getQualifierByName("blastp+go_file") != null)
{
final String DEFAULT_MAX_GO_BLAST_HITS = "10";
final String max_go_blast_hits;
final String max_go_blast_hits_from_options =
Options.getOptions ().getProperty ("mess_blast_go_hits");
externalEdit(new String[] { "-blastp+go", "-maxhits",
max_go_blast_hits, "-euk" });
externalEdit(new String[] { "-blastp+go", "-maxhits",
max_go_blast_hits });
if(Options.isUnixHost())
{
JButton oo_edit_button = new JButton("ObjectEdit");
location_button_panel.add(oo_edit_button);
final uk.ac.sanger.artemis.editor.BigPane bp =
new uk.ac.sanger.artemis.editor.BigPane(getEntryInformation());
oo_edit_button.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
String qualifier_txt = qualifier_text_area.getText();
File base_dir = getBaseDirectoryFromEntry(edit_entry);
String baseDirStr = "";
if(base_dir != null)
baseDirStr = base_dir.getAbsolutePath() +
System.getProperty("file.separator");
StringReader strRead = new StringReader(qualifier_txt);
BufferedReader buff = new BufferedReader(strRead);
String line;
final Hashtable dataFile = new Hashtable();
while((line = buff.readLine()) != null)
{
if(line.startsWith("/fasta_file="))
{
if((ind = line.indexOf(':'))>-1)
line = baseDirStr+line.substring(ind+1);
else
line = baseDirStr+line.substring(13);
ind = line.lastIndexOf("\"");
line = line.substring(0, ind);
Vector v;
if(dataFile.containsKey("fasta"))
v = (Vector)dataFile.get("fasta");
else
v = new Vector();
v.add(line);
dataFile.put("fasta",v);
if((ind = line.indexOf(':'))>-1)
line = baseDirStr+line.substring(ind+1);
else
line = baseDirStr+line.substring(14);
ind = line.lastIndexOf("\"");
line = line.substring(0, ind);
Vector v;
if(dataFile.containsKey("blastp"))
v = (Vector)dataFile.get("blastp");
else
v = new Vector();
v.add(line);
dataFile.put("blastp",v);
if((ind = line.indexOf(':'))>-1)
line = line.substring(ind+1);
else
line = baseDirStr+line.substring(17);
ind = line.lastIndexOf("\"");
line = line.substring(0, ind);
Vector v;
if(dataFile.containsKey("blastp+go"))
v = (Vector)dataFile.get("blastp+go");
else
v = new Vector();
v.add(line);
dataFile.put("blastp+go",v);
}
}
}
catch(IOException ioe){}
FeatureEdit.this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
final ProgressThread progress = new ProgressThread(null,
"Loading Data....");
progress.start();
SwingWorker ooEd = new SwingWorker()
{
public Object construct()
{
final int this_start = this_loc.getFirstBase();
final int this_end = this_loc.getLastBase();
FeaturePredicate predicate = new FeaturePredicate()
{
public boolean testPredicate (final Feature feature)
{
final int start = loc.getFirstBase();
final int end = loc.getLastBase();
if((start > this_start &&
start < this_end) ||
(end > this_start &&
end < this_end))
{
final FeatureVector overlapFeatures = new FeatureVector();
final FeatureEnumeration featureEnum = entry_group.features();
while(featureEnum.hasMoreFeatures())
{
Feature this_feature = featureEnum.nextFeature();
if(predicate.testPredicate(this_feature))
overlapFeatures.add(this_feature);
}
// show object editor
if(dataFile.size() > 0)
bp.set(dataFile, qualifier_text_area, overlapFeatures,
else
JOptionPane.showMessageDialog(null,"No results files.",
"Warning",
JOptionPane.WARNING_MESSAGE);
}
catch(ArrayIndexOutOfBoundsException e)
{
JOptionPane.showMessageDialog(null,"No results files.",
"Warning",
JOptionPane.WARNING_MESSAGE);
}
progress.finished();
FeatureEdit.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
return null;
}
};
ooEd.start();
}
});
}
cancel_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(edit_feature.getEntry() != null)
stopListening();
if(!getFeature().isReadOnly())
{
ok_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(setFeature())
{
stopListening();
if(propertiesPanel != null)
propertiesPanel.updateObsoleteSettings();
apply_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setFeature();
final JPanel ok_cancel_update_panel = new JPanel(flow_layout);
matchForm = new MatchPanel(getFeature(),
(DocumentEntry)getFeature().getEmblFeature().getEntry());
final JCheckBox tabbedView = new JCheckBox("Tabbed View", isTabbedView);
tabbedView.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
isTabbedView = tabbedView.isSelected();
addGffAnnotationView(lower_panel);
lower_panel.revalidate();
lower_panel.repaint();
}
});
ok_cancel_update_panel.add(tabbedView);
fillerBox.add(Box.createHorizontalStrut(
tabbedView.getPreferredSize().width ));
}
else
lower_panel.add(new JScrollPane(qualifier_text_area), "Center");
if(!getFeature().isReadOnly())
ok_cancel_update_panel.add(ok_button);
ok_cancel_update_panel.add(cancel_button);
if(!getFeature().isReadOnly())
ok_cancel_update_panel.add(apply_button);
ok_cancel_update_panel.add(fillerBox);
add(ok_cancel_update_panel, "South");
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* Refresh the annotation for the active feature
*/
private void refresh()
{
// refresh from the database
final DatabaseDocument originalDocument =
(DatabaseDocument)((DocumentEntry)edit_feature.getEmblFeature().getEntry()).getDocument();
final Set uniquenames = ((GFFStreamFeature)edit_feature.getEmblFeature()).getSegmentRangeStore().keySet();
final Iterator it = uniquenames.iterator();
final String uniquename = (String)it.next();
final DatabaseDocument newDocument = new DatabaseDocument(originalDocument,
uniquename, null, true, null);
newDocument.setReadChildren(false);
try
{
DatabaseDocumentEntry dbentry = new DatabaseDocumentEntry(newDocument, null);
uk.ac.sanger.artemis.io.Feature databaseFeature = dbentry.getAllFeatures().featureAt(0);
// compare timelastmodified
Qualifier qualifier = edit_feature.getQualifierByName("timelastmodified");
String active_timelastmodified = (String)qualifier.getValues().get(0);
qualifier = databaseFeature.getQualifierByName("timelastmodified");
String database_timelastmodified = (String)qualifier.getValues().get(0);