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
{
/** 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 - 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.
**/
private 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.entry_group = entry_group;
this.selection = selection;
this.entry_information = edit_feature.getEntry().getEntryInformation();
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.
**/
}
/**
* Remove an ActionListener from the Cancel JButton of this FeatureEdit.
**/
}
/**
* Add an ActionListener to the Apply JButton of this FeatureEdit.
**/
}
/**
* 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();
}
});
}
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.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.setSelection(selection);
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);
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
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
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);
}
edit_feature.getQualifiers().removeAllElements();
edit_feature.getQualifiers().addAll(new_qv);
updateQualifiers();
}
catch(EntryInformationException e) {}
catch(IOException e) {}
}
/**
* Add the annotation view as tabbed or in a single pane
* @param lower_panel
*/
private void addGffAnnotationView(final JPanel lower_panel)
{
Component c[] = lower_panel.getComponents();
if(isTabbedView)
{
for(int i=0; i<c.length; i++)
{
if(c[i] instanceof JScrollPane)
lower_panel.remove(c[i]);