Newer
Older
/* GffPanel.java
* This file is part of Artemis
*
* Copyright (C) 2007 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/genebuilder/gff/PropertiesPanel.java,v 1.11 2009-08-17 12:50:42 tjc Exp $
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Set;
import uk.ac.sanger.artemis.FeatureChangeEvent;
import uk.ac.sanger.artemis.FeatureChangeListener;
import uk.ac.sanger.artemis.Feature;
import uk.ac.sanger.artemis.chado.ChadoTransactionManager;
import uk.ac.sanger.artemis.components.genebuilder.GeneUtils;
import uk.ac.sanger.artemis.components.genebuilder.JExtendedComboBox;
import uk.ac.sanger.artemis.editor.MultiLineToolTipUI;
import uk.ac.sanger.artemis.io.ChadoCanonicalGene;
import uk.ac.sanger.artemis.io.Qualifier;
import uk.ac.sanger.artemis.io.QualifierVector;
public class PropertiesPanel extends JPanel
implements FeatureChangeListener
{
private static final long serialVersionUID = 1L;
private QualifierVector gffQualifiers;
private JTextField primaryNameTextField;
private JCheckBox obsoleteField;
private JCheckBox partialField5prime;
private JCheckBox partialField3prime;
/** controls if this panel is automatically closed or open */
/** track if feature isObsolete flag has changed */
protected boolean obsoleteChanged = false;
private boolean partialChanged = false;
private boolean showParent = true;
private boolean showOptions = true;
private boolean showTimeLastModified = true;
static
{
MultiLineToolTipUI.initialize();
}
public PropertiesPanel(final Feature feature)
public PropertiesPanel(final Feature feature,
boolean showNames,
boolean showParent,
boolean showOptions,
boolean showTimeLastModified)
this.showOptions = showOptions;
this.showParent = showParent;
this.showTimeLastModified = showTimeLastModified;
setBackground(Color.WHITE);
updateFromFeature(feature);
}
/**
* Return true if this is a CV qualifier
* @param qualifier
* @return
*/
public static boolean isPropertiesTag(final Qualifier qualifier, final Feature feature)
qualifier.getName().equals("Name") ||
qualifier.getName().equals("feature_relationship_rank") ||
qualifier.getName().equals("isObsolete") ||
qualifier.getName().equals("Start_range") ||
qualifier.getName().equals("End_range") ||
ChadoTransactionManager.isSynonymTag(qualifier.getName(),
(GFFStreamFeature)feature.getEmblFeature()))
JPanel gridPanel = new JPanel(new GridBagLayout());
gridPanel.setBackground(Color.white);
{
addParent(c, gridPanel, "Parent");
addParent(c, gridPanel, "Derives_from");
}
// phase of translation wrt / codon_start
if(feature.getEntry().getEntryInformation().isValidQualifier(
feature.getKey(), "codon_start"))
// add buttons and timelastmodified
if(showTimeLastModified)
return gridPanel;
}
/**
* Add uniquename and name to the panel.
* @param c
* @param gridPanel
*/
{
Qualifier idQualifier = gffQualifiers.getQualifierByName("ID");
Qualifier nameQualifier = gffQualifiers.getQualifierByName("Name");
uniquenameTextField = new JTextField(uniquename);
uniquenameTextField.setPreferredSize(calcPreferredMaxTextFieldWidth());
JLabel idField = new JLabel("ID ");
idField.setFont(getFont().deriveFont(Font.BOLD));
idField.setHorizontalAlignment(SwingConstants.RIGHT);
idField.setPreferredSize(calcPreferredLabelWidth());
c.ipadx = 5;
c.anchor = GridBagConstraints.EAST;
c.gridx = 1;
c.ipadx = 0;
c.anchor = GridBagConstraints.WEST;
gridPanel.add(uniquenameTextField, c);
Qualifier featIdQualifier = gffQualifiers.getQualifierByName("feature_id");
if (featIdQualifier != null)
{
Qualifier timeQualifier = gffQualifiers.getQualifierByName("timelastmodified");
String time = null;
if (timeQualifier != null)
String parent = getParentString();
String tt = "feature_id=" +
(parent == null ? "" : "\n"+parent)+
(time == null ? "" : "\n"+time);
idField.setToolTipText(tt);
uniquenameTextField.setToolTipText(tt);
}
if(feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
uniquenameTextField.setEditable(false);
if (!feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
primaryNameTextField.setPreferredSize(calcPreferredMaxTextFieldWidth());
primaryNameTextField.setText((String) nameQualifier.getValues().get(0));
c.ipadx = 5;
c.anchor = GridBagConstraints.EAST;
JLabel lab = new JLabel(" Name");
lab.setFont(getFont().deriveFont(Font.BOLD));
gridPanel.add(lab, c);
gridPanel.add(primaryNameTextField, c);
}
ActionListener addAction = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
addSynonym();
}
};
AddButton addSynonymButton = new AddButton(addAction, "Add Synonym");
}
/**
* Get the parent feature name.
* @return
*/
private String getParentString()
{
Qualifier parentQual = gffQualifiers.getQualifierByName("Parent");
if(parentQual != null &&
parentQual.getValues().size() == 1)
return "Parent: "+parentQual.getValues().get(0);
Qualifier derivesFromQual = gffQualifiers.getQualifierByName("Derives_from");
if(derivesFromQual != null &&
derivesFromQual.getValues().size() == 1)
return "Derives from: "+derivesFromQual.getValues().get(0);
return null;
}
/**
* Add Parent or Derives_from.
* @param c
* @param gridPanel
*/
private void addParent(GridBagConstraints c,
JPanel gridPanel,
Qualifier parentQualifier = gffQualifiers.getQualifierByName(parentName);
if(parentQualifier != null &&
parentQualifier.getValues().size() == 1)
{
parentField.setFont(getFont().deriveFont(Font.BOLD));
c.gridx = 0;
c.ipadx = 5;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.EAST;
gridPanel.add(parentField, c);
JTextField parent = new JTextField(" "+ parentQualifier.getValues().get(0));
parent.setPreferredSize(calcPreferredMaxTextFieldWidth());
parent.setBorder(BorderFactory.createEmptyBorder());
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
gridPanel.add(parent, c);
return;
}
}
/**
* Add synonyms to the panel.
* @param c
* @param gridPanel
* @param nrows
*/
if( ChadoTransactionManager.isSynonymTag(qualifier.getName(),
(GFFStreamFeature)feature.getEmblFeature()) &&
isSystematicId(qualifier.getName()))
if( ChadoTransactionManager.isSynonymTag(qualifier.getName(),
(GFFStreamFeature)feature.getEmblFeature()) &&
!isSystematicId(qualifier.getName()))
}
/**
* Add partial and obsolete options to the panel.
* @param c
* @param gridPanel
*/
final Qualifier isPartialQualfier5;
final Qualifier isPartialQualfier3;
isPartialQualfier5 = gffQualifiers.getQualifierByName("Start_range");
isPartialQualfier3 = gffQualifiers.getQualifierByName("End_range");
else
isPartialQualfier3 = gffQualifiers.getQualifierByName("Start_range");
isPartialQualfier5 = gffQualifiers.getQualifierByName("End_range");
Box optionsBox = Box.createHorizontalBox();
partialField5prime = new JCheckBox("partial 5'",
Dimension d = calcPreferred(partialField5prime.getPreferredSize().width);
partialField5prime.setPreferredSize(d);
partialField5prime.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
checkPartial();
}
});
optionsBox.add(partialField5prime);
partialField3prime = new JCheckBox("partial 3'",
partialField3prime.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
checkPartial();
}
});
Qualifier obsoleteQual = gffQualifiers.getQualifierByName("isObsolete");
obsoleteField = new JCheckBox("obsolete", (obsoleteQual == null ? false :
Boolean.parseBoolean(obsoleteQual.getValues().get(0))));
obsoleteField.setPreferredSize(calcPreferred(obsoleteField.getPreferredSize().width));
obsoleteField.setOpaque(false);
obsoleteField.addActionListener(new ActionListener()
{
int result = JOptionPane.showConfirmDialog(
PropertiesPanel.this, "Change this feature to be "+
(obsoleteField.isSelected() ? "obsolete!" : "not obsolete!"),
"Change obsolete option", JOptionPane.OK_CANCEL_OPTION);
if(result == JOptionPane.CANCEL_OPTION)
obsoleteField.setSelected(!obsoleteField.isSelected());
optionsBox.add(obsoleteField);
c.gridx = 0;
c.anchor = GridBagConstraints.WEST;
c.gridwidth = GridBagConstraints.REMAINDER;
gridPanel.add(optionsBox, c);
c.gridwidth = 1;
{
Qualifier timeQualifier = gffQualifiers.getQualifierByName("timelastmodified");
if (timeQualifier != null)
{
timeLabel.setEnabled(false);
timeLabel.setToolTipText("time last modified");
c.gridx = 4;
c.gridwidth = GridBagConstraints.REMAINDER;
c.anchor = GridBagConstraints.EAST;
gridPanel.add(timeLabel,c);
}
}
removeAll();
if(gffQualifiers != null)
feature.removeFeatureChangeListener(this);
gffQualifiers = feature.getQualifiers().copy();
gffQualifiers = new QualifierVector();
final QualifierVector qualifiers = feature.getQualifiers();
gffQualifiers.addElement(qualifier.copy());
}
feature.addFeatureChangeListener(this);
public QualifierVector getGffQualifiers(final Feature feature)
{
// check editable components for changes
Qualifier idQualifier = gffQualifiers.getQualifierByName("ID");
final String newName = uniquenameTextField.getText().trim();
final String oldName = ((String) (idQualifier.getValues().get(0))).trim();
GFFStreamFeature gffFeature = (GFFStreamFeature)feature.getEmblFeature();
if(gffFeature.getChadoGene() != null)
{
Set<uk.ac.sanger.artemis.io.Feature> children =
gffFeature.getChadoGene().getChildren(gffFeature);
gffFeature.getChadoGene().updateUniqueName(oldName, newName, children);
}
if(!feature.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))
Qualifier nameQualifier = gffQualifiers.getQualifierByName("Name");
if( (nameQualifier != null &&
!nameQualifier.getValues().get(0).equals(primaryNameTextField.getText())) ||
(primaryNameTextField != null && !primaryNameTextField.getText().equals("")))
gffQualifiers.remove(nameQualifier);
final String newName = primaryNameTextField.getText().trim();
nameQualifier = new Qualifier("Name", newName);
gffQualifiers.addElement(nameQualifier);
}
}
if(phaseButtonGroup != null)
{
String selectionCmd = phaseButtonGroup.getSelection().getActionCommand();
Qualifier phaseQualifier = gffQualifiers.getQualifierByName("codon_start");
if(phaseQualifier == null)
{
if(!selectionCmd.equals(""))
{
phaseQualifier = new Qualifier("codon_start", selectionCmd);
gffQualifiers.addElement(phaseQualifier);
}
}
else
{
if(!oldPhase.equals(phaseButtonGroup))
{
gffQualifiers.remove(phaseQualifier);
if(!selectionCmd.equals(""))
{
phaseQualifier = new Qualifier("codon_start", selectionCmd);
gffQualifiers.addElement(phaseQualifier);
}
}
}
}
Qualifier isObsoleteQualifier = gffQualifiers.getQualifierByName("isObsolete");
if(isObsoleteQualifier != null)
{
String isObsoleteNew = Boolean.toString(obsoleteField.isSelected());
if (!isObsoleteNew.equals(isObsoleteOld))
{
gffQualifiers.remove(isObsoleteQualifier);
isObsoleteQualifier = new Qualifier("isObsolete", isObsoleteNew);
gffQualifiers.addElement(isObsoleteQualifier);
obsoleteChanged = true;
}
}
Qualifier isPartial5primeQualifier;
if(feature.isForwardFeature())
isPartial5primeQualifier = gffQualifiers.getQualifierByName("Start_range");
isPartial5primeQualifier = gffQualifiers.getQualifierByName("End_range");
partialChanged = true;
}
gffQualifiers.addElement(new Qualifier("Start_range",".,."));
gffQualifiers.addElement(new Qualifier("End_range",".,."));
}
Qualifier isPartial3primeQualifier;
if(feature.isForwardFeature())
isPartial3primeQualifier = gffQualifiers.getQualifierByName("End_range");
isPartial3primeQualifier = gffQualifiers.getQualifierByName("Start_range");
partialChanged = true;
}
gffQualifiers.addElement(new Qualifier("End_range",".,."));
gffQualifiers.addElement(new Qualifier("Start_range",".,."));
* If the partial/isObsolete qualifier for this feature has been changed this
* method updates the partial/isObsolete qualifier of the children feature.
public void updateSettings()
if(partialChanged)
updatePartialSettings((GFFStreamFeature)feature.getEmblFeature());
if(!obsoleteChanged)
return;
obsoleteChanged = false;
updateObsoleteSettings((GFFStreamFeature)feature.getEmblFeature());
}
public static void updateObsoleteSettings(GFFStreamFeature gffFeature)
{
Qualifier isObsoleteQualifier = gffFeature.getQualifierByName("isObsolete");
String isObsoleteNew = isObsoleteQualifier.getValues().get(0);
gffFeature.setVisible(!isObsoleteNew.equals("true"));
Set<uk.ac.sanger.artemis.io.Feature> children =
gffFeature.getChadoGene().getChildren(gffFeature);
if(children.size() > 0)
{
Qualifier idQualifier = gffFeature.getQualifierByName("ID");
int select = JOptionPane.showConfirmDialog(null,
"Make children of "+idQualifier.getValues().get(0)+"\n"+
(isObsoleteNew.equals("true") ? "obsolete?" : "not obsolete?"),
"Update Children",
JOptionPane.YES_NO_OPTION);
if(select == JOptionPane.YES_OPTION)
{
try
{
Iterator<uk.ac.sanger.artemis.io.Feature> it = children.iterator();
while(it.hasNext())
{
GFFStreamFeature gffChildFeature = (GFFStreamFeature)it.next();
Feature f = (Feature)gffChildFeature.getUserData();
f.setQualifier(new Qualifier("isObsolete", isObsoleteNew));
gffChildFeature.setVisible(true);
if(isObsoleteNew.equals("true") ||
GeneUtils.isHiddenFeature( gffChildFeature.getKey().getKeyString() ))
gffChildFeature.setVisible(false);
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
/**
* Change partial settings of child featuers.
* @param gffFeature
*/
private void updatePartialSettings(GFFStreamFeature gffFeature)
{
if(!partialChanged)
return;
partialChanged = false;
if(gffFeature.getChadoGene() == null)
return;
Qualifier fminQualifier = gffFeature.getQualifierByName("Start_range");
Qualifier fmaxQualifier = gffFeature.getQualifierByName("End_range");
ChadoCanonicalGene chadoGene = gffFeature.getChadoGene();
Set<uk.ac.sanger.artemis.io.Feature> children = chadoGene.getChildren(gffFeature);
if(children.size() > 0)
{
int select = JOptionPane.showConfirmDialog(null,
"Update partial setting on child features?",
"Update Children", JOptionPane.YES_NO_OPTION);
if(select != JOptionPane.YES_OPTION)
return;
try
{
Iterator<uk.ac.sanger.artemis.io.Feature> it = children.iterator();
while(it.hasNext())
{
final GFFStreamFeature gffChildFeature = (GFFStreamFeature)it.next();
final Feature f = (Feature)gffChildFeature.getUserData();
final String keyStr = f.getKey().getKeyString();
if(keyStr.equals("five_prime_UTR") || keyStr.equals("three_prime_UTR"))
{
String fName = chadoGene.getQualifier(gffChildFeature, "ID");
boolean isFwd = !f.getLocation().isComplement();
if(fName != null && !chadoGene.isFirstUtr(fName, isFwd))
continue;
if( (keyStr.equals("five_prime_UTR") && isFwd) ||
(keyStr.equals("three_prime_UTR") && !isFwd) )
{
if(fminQualifier != null)
f.setQualifier(new Qualifier("Start_range",".,."));
f.removeQualifierByName("Start_range");
}
else
{
if(fmaxQualifier != null)
f.setQualifier(new Qualifier("End_range",".,."));
f.removeQualifierByName("End_range");
f.setQualifier(new Qualifier("Start_range",".,."));
f.removeQualifierByName("Start_range");
f.setQualifier(new Qualifier("End_range",".,."));
f.removeQualifierByName("End_range");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
/**
* Partial settings are made on the gene or transcript features.
* Provide a warning if this is not the case.
*/
private void checkPartial()
{
String keyStr = feature.getKey().getKeyString();
if(keyStr.equals("polypeptide") ||
keyStr.equals("CDS") ||
keyStr.equals("pseudogenic_exon"))
{
JOptionPane.showMessageDialog(null,
"Partial settings should be updated on the transcript\n"+
"or gene feature not a "+keyStr+". Please make this change\n"+
"on the transcript or gene feature now.",
"Error", JOptionPane.WARNING_MESSAGE);
}
}
private void removeSynonym(String synonymName, String qualifierValue)
{
int select = JOptionPane.showConfirmDialog(null,
"Delete "+qualifierValue+"?",
"Select synonym type", JOptionPane.OK_CANCEL_OPTION);
StringVector values =
gffQualifiers.getQualifierByName(synonymName).getValues();
if(values.size()==1)
gffQualifiers.removeQualifierByName(synonymName);
else
{
int index = gffQualifiers.indexOfQualifierWithName(synonymName);
values.remove(qualifierValue);
gffQualifiers.remove(index);
gffQualifiers.add(index, new Qualifier(synonymName, values));
}
removeAll();
add(createGffQualifiersComponent());
revalidate();
final Vector<CvTerm> synonyms = DatabaseDocument.getCvterms("",
final JExtendedComboBox list = new JExtendedComboBox(synonyms);
final String options[] = { "CANCEL", "NEXT>"};
int select = JOptionPane.showOptionDialog(null, list,
"Select synonym type",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE,
if(select == 0)
return;
Box xBox = Box.createHorizontalBox();
final String synonymName = ((CvTerm)list.getSelectedItem()).getName();
final JLabel name = new JLabel( synonymName );
xBox.add(name);
final JTextField newSynonym = new JTextField(15);
xBox.add(newSynonym);
final JCheckBox current = new JCheckBox("make current", true);
select = JOptionPane.showConfirmDialog(null, xBox,
"Input name", JOptionPane.OK_CANCEL_OPTION);
if(select == JOptionPane.CANCEL_OPTION || newSynonym.getText().equals(""))
return;
Qualifier synonymQualifier = gffQualifiers.getQualifierByName(synonymName);
String newSynonymValue = newSynonym.getText();
newSynonymValue = newSynonymValue + ";current=false";
if(synonymQualifier == null)
{
synonymQualifier = new Qualifier(synonymName, newSynonymValue);
gffQualifiers.add(synonymQualifier);
}
else
synonymQualifier.addValue(newSynonymValue);
final StringVector newValues = synonymQualifier.getValues();
int index = gffQualifiers.indexOfQualifierWithName(synonymName);
if(index == -1)
gffQualifiers.setQualifier(new Qualifier(synonymName,newValues));
else
{
gffQualifiers.remove(index);
gffQualifiers.add(index, new Qualifier(synonymName,newValues));
}
removeAll();
add(createGffQualifiersComponent());
revalidate();
}
/**
* Add codon_start component to the properties panel
* @param c
* @param gridPanel
*/
private void addPhaseComponent(final GridBagConstraints c, final JPanel gridPanel)
phaseNone.setOpaque(false);
phaseNone.setActionCommand("");
phaseButtonGroup.add(phaseNone);
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.NONE;
c.ipadx = 5;
JLabel lab = new JLabel("Codon Start");
lab.setFont(getFont().deriveFont(Font.BOLD));
gridPanel.add(lab, c);
Qualifier qualifierCodonStart = gffQualifiers.getQualifierByName("codon_start");
for(int i=1; i<4; i++)
{
String s = Integer.toString(i);
JRadioButton phase = new JRadioButton(s);
phase.setOpaque(false);
phase.setActionCommand(s);
phaseButtonGroup.add(phase);
if(qualifierCodonStart != null && i == codon_start)
{
empty = false;
phase.setSelected(true);
}
xBox.add(phase);
}
xBox.add(phaseNone);
xBox.add(Box.createHorizontalGlue());
c.anchor = GridBagConstraints.WEST;
c.ipadx = 0;
/**
* Add the synonym components
* @param qualifier
* @param c
* @param gridPanel
*/
private void addSynonymComponent(final Qualifier qualifier,
final GridBagConstraints c,
{
empty = false;
final StringVector values = qualifier.getValues();
String name = qualifier.getName();
if(name.equals("previous_systematic_id"))
name = "prev_sys_id";
final JLabel sysidField = new JLabel(name+" ");
sysidField.setFont(getFont().deriveFont(Font.BOLD));
sysidField.setHorizontalAlignment(SwingConstants.RIGHT);
sysidField.setPreferredSize(calcPreferredLabelWidth());
c.gridx = 1;
c.anchor = GridBagConstraints.WEST;
Box synBox = Box.createHorizontalBox();
String strs[] = val.split(";");
JLabel syn = new JLabel(" "+ strs[0] + ";");
syn.setPreferredSize(calcPreferred(syn.getPreferredSize().width));
ActionListener removeAction = new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
removeSynonym(qualifier.getName(), val);
}
};
c.gridwidth = GridBagConstraints.REMAINDER;
gridPanel.add(synBox, c);
c.gridwidth = 1;
public void featureChanged(FeatureChangeEvent event)
{
updateFromFeature(event.getFeature());
}
public boolean isEmpty()
{
return empty;
}
public void setObsoleteChanged(boolean obsoleteChanged)
{
obsoleteField.setSelected(obsoleteChanged);
}
private Dimension calcPreferredLabelWidth()
int maxLabelWidth = new JLabel("prev_sys_id ").getPreferredSize().width;
return calcPreferred(maxLabelWidth);
}
private Dimension calcPreferredMaxTextFieldWidth()
{
int maxLabelWidth = new JLabel("previous_systematic_id ").getPreferredSize().width;
int preferredHeight = fm.getHeight()+fm.getDescent()+4;
Dimension d = super.getPreferredSize();
d.height = preferredHeight;
d.width = w;
return d;
{
Border grayline = BorderFactory.createLineBorder(Color.gray);
setBorder(BorderFactory.createTitledBorder(grayline,
feature.getKey().getKeyString()));
}