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.30 2007-03-19 10:15:03 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.OutOfDateException;
import uk.ac.sanger.artemis.io.LocationParseException;
import uk.ac.sanger.artemis.io.InvalidRelationException;
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.cv.CVPanel;
import uk.ac.sanger.artemis.components.genebuilder.ortholog.OrthologPanel;
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;
import javax.swing.*;
/**
* FeatureEdit class
*
* @author Kim Rutherford
* @version $Id: FeatureEdit.java,v 1.30 2007-03-19 10:15:03 tjc Exp $
implements EntryChangeListener, FeatureChangeListener
{
/**
*
*/
private static final long serialVersionUID = 1L;
/** Used to get current time/date in externalEdit(). */
private static java.util.Calendar calendar =
java.util.Calendar.getInstance();
/** 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;
/** ortholog/paralog tab */
private OrthologPanel orthologForm;
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();
}
});
}
public void setActiveFeature(final Feature edit_feature)
{
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(gffPanel != null)
getFeature().removeFeatureChangeListener(gffPanel);
if(orthologForm != null)
getFeature().removeFeatureChangeListener(orthologForm);
}
/**
* 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
{
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 = new QualifierTextArea();
qualifier_text_area.setWrapStyleWord(true);
new KeyChoice(getEntryInformation(),getFeature().getKey());
final JPanel key_and_qualifier_panel = new JPanel();
location_text.setBackground(Color.white);
key_and_qualifier_panel.setLayout(new BorderLayout());
key_and_qualifier_panel.add(key_panel, "West");
qualifier_choice = new QualifierChoice(getEntryInformation(),
final JPanel qualifier_panel = new JPanel();
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();
lower_panel.add(outer_location_button_panel, "North");
outer_location_button_panel.setLayout(new BorderLayout());
final JPanel location_button_panel = new JPanel();
outer_location_button_panel.add(location_button_panel, "West");
final JPanel location_panel = new JPanel();
location_panel.setLayout(new BorderLayout());
location_panel.add(new JLabel("location: "), "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 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();
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();
try
{
while((line = buff.readLine()) != null)
{
if(line.startsWith("/fasta_file="))
{
int ind = line.lastIndexOf("\"");
if(ind > -1)
dataFile.put("fasta", baseDirStr+line.substring(13,ind));
}
else if(line.startsWith("/blastp_file="))
{
int ind = line.lastIndexOf("\"");
if(ind > -1)
dataFile.put("blastp", baseDirStr+line.substring(14,ind));
}
else if(line.startsWith("/blastp+go_file="))
{
int ind = line.lastIndexOf("\"");
if(ind > -1)
dataFile.put("blastp+go", baseDirStr+line.substring(17,ind));
}
}
}
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
bp.set(dataFile, qualifier_text_area, overlapFeatures,
}
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();
apply_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setFeature();
final JPanel ok_cancel_update_panel = new JPanel(flow_layout);
if(((DocumentEntry)getFeature().getEmblFeature().getEntry()).getDocument()
instanceof DatabaseDocument)
{
cvForm = new CVPanel(getFeature());
// tabbed pane of core and cv annotaion
JTabbedPane tabbedPane = new JTabbedPane();
JScrollPane jspCore = new JScrollPane(qualifier_text_area);
JScrollPane jspCV = new JScrollPane(cvForm);
jspCV.setPreferredSize(jspCore.getPreferredSize());
tabbedPane.add("CV", jspCV);
orthologForm = new OrthologPanel(getFeature());
JScrollPane jspOrtholog = new JScrollPane(orthologForm);
jspCV.setPreferredSize(jspOrtholog.getPreferredSize());
tabbedPane.add("Ortholog", jspOrtholog);
gffPanel = new GffPanel(getFeature());
JScrollPane jspGff = new JScrollPane(gffPanel);
jspGff.setPreferredSize(jspCore.getPreferredSize());
tabbedPane.add("GFF", jspGff);
lower_panel.add(tabbedPane, "Center");
}
else
lower_panel.add(new JScrollPane(qualifier_text_area), "Center");
/**
* Return the dirtectory that the given entry was read from.
**/
private File getBaseDirectoryFromEntry(final Entry entry)
{
final uk.ac.sanger.artemis.io.Entry embl_entry = entry.getEMBLEntry();
if(embl_entry instanceof DocumentEntry)
{
final DocumentEntry document_entry =(DocumentEntry) embl_entry;
if(document_entry.getDocument() instanceof FileDocument)
{
final FileDocument file_document =
(FileDocument) document_entry.getDocument();
if(file_document.getFile().getParent() != null)
return new File(file_document.getFile().getParent());
}
}
return null;
}
/**
* Read the key, location and qualifier information from the feature and
* update the components.
**/
private void updateFromFeature()
{
datestamp = getFeature().getDatestamp();
updateKey();
updateLocation();
updateQualifiers();
}
/**
* Read the location from the feature and update the location field.
**/
private void updateLocation()
{
location_text.setText(getFeature().getLocation().toStringShort());
private void complementLocation()
{
if(rationalizeLocation())
{
if(location_text.getText().startsWith("complement("))
{
final String new_text = location_text.getText().substring(11);
new_text.substring(0, new_text.length () - 1);
location_text.setText(new_text2);
}
/**
* Tidy the qualifiers by removing any indication that the annotation has
* been transferred from another gene. Remove the "transferred_" part of
* all qualifier names and the "[[FROM sc_001234 abc1]]" bit of each
* corresponding qualifier value.
**/
private void tidy() throws QualifierParseException
{
final StringBuffer buffer = new StringBuffer();
qualifier_text_area.getParsedQualifiers(getEntryInformation());
for(int qualifier_index = 0; qualifier_index < qualifiers.size();
++qualifier_index)
{
final Qualifier this_qualifier = (Qualifier)qualifiers.elementAt(qualifier_index);
getEntryInformation().getQualifierInfo(this_qualifier.getName());
StreamQualifier.toStringVector(qualifier_info, this_qualifier);
for(int value_index = 0; value_index < qualifier_strings.size();
++value_index)
{
private void tidyGO() throws QualifierParseException
{
String qualifier_txt = qualifier_text_area.getText();
StringReader strRead = new StringReader(qualifier_txt);
BufferedReader buff = new BufferedReader(strRead);
String line;
final Vector qual_str = new Vector();
try
{
while((line = buff.readLine()) != null)
qual_str.add(line);
}
catch(IOException ioe){}
Comparator comparator = new Comparator()
{
public int compare (Object fst, Object snd)
{