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.70 2009-09-24 15:01:27 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.BasicGeneBuilderFrame;
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.ReferencesPanel;
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.70 2009-09-24 15:01:27 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;
private static UserDefinedQualifier userDefinedQualifierFrame;
/**
* 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();
if(userDefinedQualifierFrame != null)
userDefinedQualifierFrame.setVisible(false);
return entry_group.getSequenceEntry().getBases().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();
if(edit_feature.getEntry() != null)
{
edit_feature.getEntry().addEntryChangeListener(this);
edit_feature.addFeatureChangeListener(this);
}
/**
* 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 flowLayoutZeroHVgap = new FlowLayout(FlowLayout.LEADING, 0, 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(flowLayoutZeroHVgap);
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));
"evidence=ISS; db_xref=GO_REF:0000001; " +
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 JToolBar location_button_panel = new JToolBar();
location_button_panel.setRollover(true);
//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");
complement_button.setToolTipText("Complement position");
location_button_panel.add(complement_button);
complement_button.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
complementLocation();
if(GeneUtils.isDatabaseEntry(getFeature().getEmblFeature()))
{
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");
grab_button.setToolTipText("Add selected base range from feature coordinates");
location_button_panel.add(grab_button);
grab_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
final JButton remove_button = new JButton("Remove Range");
remove_button.setToolTipText("Remove selected base range from feature coordinates");
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");
goto_button.setToolTipText("Goto and select this feature");
{
public void actionPerformed(ActionEvent e)
{
goto_event_source.gotoBase(getFeature().getFirstBaseMarker());
getSelection().set(getFeature());
/* 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
{
"Cannot tidy - qualifier error: " +
exception.getMessage());
final JButton transferAnnotationBbutton = new JButton("TAT");
location_button_panel.add(transferAnnotationBbutton);
transferAnnotationBbutton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
new TransferAnnotationTool(getFeature(), entry_group, matchForm);
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<String, Vector<String>> dataFile = new Hashtable<String, Vector<String>>();
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("\"");
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("\"");
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("\"");
if(dataFile.containsKey("blastp+go"))
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();
}
});
}
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
final JButton userQualifiers = new JButton("User Qualifiers");
userQualifiers.setToolTipText("User defined qualifier selection");
location_button_panel.add(userQualifiers);
userQualifiers.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(userDefinedQualifierFrame == null)
{
userDefinedQualifierFrame = new UserDefinedQualifier();
userDefinedQualifierFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
}
userDefinedQualifierFrame.pack();
final JFrame topFrame =
(JFrame) SwingUtilities.getWindowAncestor(FeatureEdit.this);
Point p = topFrame.getLocationOnScreen();
p.x -= userDefinedQualifierFrame.getWidth();
if(p.x < 10)
p.x = 10;
userDefinedQualifierFrame.setLocation(p);
userDefinedQualifierFrame.setQualifierTextArea(qualifier_text_area);
userDefinedQualifierFrame.setVisible(true);
}
});
cancel_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(edit_feature.getEntry() != null)
stopListening();
if(userDefinedQualifierFrame != null)
userDefinedQualifierFrame.setVisible(false);
if(!getFeature().isReadOnly())
{
ok_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if(setFeature())
{
stopListening();
propertiesPanel.updateSettings();
if(userDefinedQualifierFrame != null)
userDefinedQualifierFrame.setVisible(false);
apply_button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setFeature();
final JPanel ok_cancel_update_panel = new JPanel(flow_layout);
if(GeneUtils.isDatabaseEntry(getFeature().getEmblFeature()))
(DocumentEntry)getFeature().getEmblFeature().getEntry());
refPanel = new ReferencesPanel(getFeature());
refPanel.setBackground(Color.WHITE);
final JCheckBox tabbedView = new JCheckBox("Tab View", isTabbedView);
tabbedView.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
isTabbedView = tabbedView.isSelected();
addGffAnnotationView(lower_panel);
lower_panel.revalidate();
lower_panel.repaint();
}
});
final JCheckBox oneView = new JCheckBox("Overview", false);
oneView.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent e)
{
if(setFeature())
{
stopListening();
if(propertiesPanel != null)
propertiesPanel.updateSettings();
frame.dispose();
System.setProperty("basic", "true");
new BasicGeneBuilderFrame(getFeature(), entry_group,
selection, null);
}
}
});
if(((GFFStreamFeature)getFeature().getEmblFeature()).getChadoGene() != null)
ok_cancel_update_panel.add(oneView);
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");
/**
* 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<String> uniquenames = ((GFFStreamFeature)edit_feature.getEmblFeature()).getSegmentRangeStore().keySet();
final Iterator<String> it = uniquenames.iterator();
final String uniquename = it.next();
final DatabaseDocument newDocument = new DatabaseDocument(originalDocument,
uniquename, null, true, null);
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
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
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);
if(active_timelastmodified.equals(database_timelastmodified))
{
JOptionPane.showMessageDialog(this,
"No new changes found for the feature\n"+
uniquename+"\n"+
"in the database since:\n"+database_timelastmodified,
"No Updates", JOptionPane.INFORMATION_MESSAGE);
return;
}
else
{
JOptionPane.showMessageDialog(this,
"Changes found for the feature\n"+
uniquename+"\n"+
"in the database at:\n"+database_timelastmodified,
"Changes Found", JOptionPane.INFORMATION_MESSAGE);
}
final QualifierVector db_qv = databaseFeature.getQualifiers();
final QualifierVector qv = edit_feature.getQualifiers();
final QualifierVector new_qv = new QualifierVector();
for(int i=0; i<qv.size(); i++)
{
Qualifier q = (Qualifier)qv.get(i);
if(q.getName().equals("Parent") ||
q.getName().equals("Derives_from") ||
q.getName().equals("ID") )
new_qv.addQualifierValues(q);
}
for(int i=0; i<db_qv.size(); i++)
{
Qualifier q = (Qualifier)db_qv.get(i);
if(q.getName().equals("Parent") ||
q.getName().equals("Derives_from") ||
q.getName().equals("ID") )
continue;
new_qv.add(q);