1 /* GeneUtils.java 2 * 3 * This file is part of Artemis 4 * Copyright (C) 2007 Genome Research Limited 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19 * 20 **/ 21 package uk.ac.sanger.artemis.components.genebuilder; 22 23 import java.awt.BorderLayout; 24 import java.awt.Cursor; 25 import java.awt.event.ActionEvent; 26 import java.awt.event.ActionListener; 27 import java.util.Collection; 28 import java.util.Enumeration; 29 import java.util.Hashtable; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.Set; 33 import java.util.Vector; 34 35 import javax.swing.Box; 36 import javax.swing.DefaultListModel; 37 import javax.swing.JButton; 38 import javax.swing.JCheckBox; 39 import javax.swing.JFrame; 40 import javax.swing.JLabel; 41 import javax.swing.JList; 42 import javax.swing.JOptionPane; 43 import javax.swing.JPanel; 44 import javax.swing.JScrollPane; 45 46 import org.gmod.schema.general.DbXRef; 47 import org.gmod.schema.sequence.FeatureCvTerm; 48 import org.gmod.schema.sequence.FeatureDbXRef; 49 import org.gmod.schema.sequence.FeaturePub; 50 import org.gmod.schema.sequence.FeatureSynonym; 51 52 import uk.ac.sanger.artemis.chado.ClusterLazyQualifierValue; 53 import uk.ac.sanger.artemis.chado.FeatureForUpdatingResidues; 54 import uk.ac.sanger.artemis.chado.FeatureLocLazyQualifierValue; 55 import uk.ac.sanger.artemis.components.EditMenu; 56 import uk.ac.sanger.artemis.components.MessageDialog; 57 import uk.ac.sanger.artemis.components.SelectionMenu; 58 import uk.ac.sanger.artemis.io.ChadoCanonicalGene; 59 import uk.ac.sanger.artemis.io.DatabaseDocumentEntry; 60 import uk.ac.sanger.artemis.io.DatabaseInferredFeature; 61 import uk.ac.sanger.artemis.io.DocumentEntry; 62 import uk.ac.sanger.artemis.io.EntryInformationException; 63 import uk.ac.sanger.artemis.io.Feature; 64 import uk.ac.sanger.artemis.io.GFF3Encoder; 65 import uk.ac.sanger.artemis.io.GFFDocumentEntry; 66 import uk.ac.sanger.artemis.io.GFFStreamFeature; 67 import uk.ac.sanger.artemis.io.InvalidRelationException; 68 import uk.ac.sanger.artemis.io.Key; 69 import uk.ac.sanger.artemis.io.KeyVector; 70 import uk.ac.sanger.artemis.io.Location; 71 import uk.ac.sanger.artemis.io.Qualifier; 72 import uk.ac.sanger.artemis.io.QualifierLazyLoading; 73 import uk.ac.sanger.artemis.io.QualifierVector; 74 import uk.ac.sanger.artemis.io.Range; 75 import uk.ac.sanger.artemis.io.RangeVector; 76 import uk.ac.sanger.artemis.sequence.MarkerRange; 77 import uk.ac.sanger.artemis.util.ByteBuffer; 78 import uk.ac.sanger.artemis.util.DatabaseDocument; 79 import uk.ac.sanger.artemis.util.OutOfRangeException; 80 import uk.ac.sanger.artemis.util.ReadOnlyException; 81 import uk.ac.sanger.artemis.util.StringVector; 82 import uk.ac.sanger.artemis.Entry; 83 import uk.ac.sanger.artemis.EntryGroup; 84 import uk.ac.sanger.artemis.EntryVector; 85 import uk.ac.sanger.artemis.FeatureKeyQualifierPredicate; 86 import uk.ac.sanger.artemis.FeaturePredicate; 87 import uk.ac.sanger.artemis.FeatureVector; 88 import uk.ac.sanger.artemis.GotoEventSource; 89 import uk.ac.sanger.artemis.Options; 90 import uk.ac.sanger.artemis.Selection; 91 92 93 public class GeneUtils 94 { 95 private static Vector<String> hideFeatures = new Vector<String>(); 96 private static JCheckBox showObsolete = new JCheckBox("Show Obsolete Features",false); 97 private static String nonCodingTranscripts[] = 98 { "tRNA", "rRNA", "snRNA", "snoRNA", "ncRNA", "scRNA" }; 99 private static StringVector featuresToUpdateResidues = 100 Options.getOptions().getOptionValues("sequence_update_features"); 101 102 static 103 { 104 hideFeatures.add("polypeptide"); 105 hideFeatures.add(DatabaseDocument.TRANSCRIPT); 106 hideFeatures.add("pseudogenic_transcript"); 107 } 108 109 /** 110 * Used when a whole sequence is loaded in and the features are loaded 111 * lazily 112 * @param feature 113 */ addLazyQualifiers(final GFFStreamFeature feature)114 public static void addLazyQualifiers(final GFFStreamFeature feature) 115 { 116 if(feature.isLazyLoaded() || feature.getChadoLazyFeature() == null) 117 return; 118 119 // synonyms 120 final Collection featureSynonyms = feature.getChadoLazyFeature().getFeatureSynonyms(); 121 122 final Iterator it = featureSynonyms.iterator(); 123 while(it.hasNext()) 124 { 125 final FeatureSynonym featureSynonym = (FeatureSynonym) it.next(); 126 final String name = featureSynonym.getSynonym().getCvTerm().getName(); 127 String value = featureSynonym.getSynonym().getName(); 128 129 if(!featureSynonym.isCurrent()) 130 value.concat(GFF3Encoder.encode(";current=false")); 131 132 Qualifier qualifier = feature.getQualifiers().getQualifierByName(name); 133 if(qualifier == null) 134 qualifier = new Qualifier(name, value); 135 else 136 qualifier.addValue(value); 137 138 feature.getQualifiers().setQualifier(qualifier); 139 } 140 141 // dbxrefs 142 if(feature.getQualifierByName("Dbxref") == null) 143 { 144 DbXRef dbxref = feature.getChadoLazyFeature().getDbXRef(); 145 if(dbxref != null) 146 { 147 String value = dbxref.getDb().getName() + ":" + 148 dbxref.getAccession(); 149 feature.getQualifiers().setQualifier(new Qualifier("Dbxref", value)); 150 151 if(feature.isReadOnly() && feature.getKey().equals("polypeptide_domain")) 152 { 153 value= "protein motif:"+value; 154 feature.getQualifiers().setQualifier(new Qualifier("inference", value)); 155 } 156 } 157 } 158 159 160 final Collection featureDbXRefs = feature.getChadoLazyFeature().getFeatureDbXRefs(); 161 final Iterator it2 = featureDbXRefs.iterator(); 162 while(it2.hasNext()) 163 { 164 final FeatureDbXRef featureDbXRef = (FeatureDbXRef) it2.next(); 165 String value = featureDbXRef.getDbXRef().getDb().getName() + ":" + 166 featureDbXRef.getDbXRef().getAccession(); 167 168 Qualifier qualifier = feature.getQualifiers().getQualifierByName("Dbxref"); 169 if(qualifier == null) 170 qualifier = new Qualifier("Dbxref", value); 171 else 172 qualifier.addValue(value); 173 feature.getQualifiers().setQualifier(qualifier); 174 } 175 176 177 // feature cvterms (GO, product....) 178 final Collection featureCvTerms = feature.getChadoLazyFeature().getFeatureCvTerms(); 179 if(featureCvTerms != null) 180 { 181 final Iterator it3 = featureCvTerms.iterator(); 182 while(it3.hasNext()) 183 { 184 FeatureCvTerm featureCvTerm = (FeatureCvTerm)it3.next(); 185 List featureCvTermDbXRefList = null; 186 187 if(featureCvTerm.getFeatureCvTermDbXRefs() != null) 188 featureCvTermDbXRefList = new Vector(featureCvTerm.getFeatureCvTermDbXRefs()); 189 190 List featureCvTermPubList = null; 191 192 if(featureCvTerm.getFeatureCvTermPubs() != null) 193 featureCvTermPubList = new Vector(featureCvTerm.getFeatureCvTermPubs()); 194 195 ByteBuffer this_buff = new ByteBuffer(); 196 DatabaseDocument.appendControlledVocabulary(this_buff, null, featureCvTerm, 197 featureCvTermDbXRefList,featureCvTermPubList, null, false); 198 199 final String qualifierString = new String(this_buff.getBytes()); 200 int ind = qualifierString.indexOf('='); 201 final String name = qualifierString.substring(0, ind); 202 final String value = GFF3Encoder.decode( 203 qualifierString.substring(ind+1, qualifierString.length()-1)); 204 205 Qualifier qualifier = feature.getQualifiers().getQualifierByName(name); 206 if(qualifier == null) 207 qualifier = new Qualifier(name, value); 208 else 209 qualifier.addValue(value); 210 feature.getQualifiers().setQualifier(qualifier); 211 } 212 } 213 // feature pubs - literature 214 final Collection featurePubs = feature.getChadoLazyFeature().getFeaturePubs(); 215 216 if(featurePubs != null) 217 { 218 final Iterator it4 = featurePubs.iterator(); 219 while(it4.hasNext()) 220 { 221 FeaturePub featurePub = (FeaturePub) it4.next(); 222 223 Qualifier qualifier = feature.getQualifiers().getQualifierByName( 224 "literature"); 225 if(qualifier == null) 226 qualifier = new Qualifier("literature", featurePub.getPub() 227 .getUniqueName()); 228 else 229 qualifier.addValue(featurePub.getPub().getUniqueName()); 230 feature.getQualifiers().setQualifier(qualifier); 231 } 232 } 233 234 feature.setLazyLoaded(true); 235 } 236 237 /** 238 * Used to reverse complement all the gene model features 239 * @param chadoGene 240 */ complementGeneModel(final ChadoCanonicalGene chadoGene)241 public static void complementGeneModel(final ChadoCanonicalGene chadoGene) 242 { 243 if(chadoGene == null) 244 return; 245 try 246 { 247 final Feature gene = chadoGene.getGene(); 248 final boolean complement = gene.getLocation().isComplement(); 249 gene.setLocation(gene.getLocation().getComplement()); 250 final Set kids = chadoGene.getChildren(gene); 251 final Iterator it = kids.iterator(); 252 while(it.hasNext()) 253 { 254 final Feature f = (Feature)it.next(); 255 final RangeVector rv = f.getLocation().getRanges(); 256 rv.reverse(); 257 f.setLocation(new Location(rv, !complement)); 258 } 259 } 260 catch(ReadOnlyException e) 261 { 262 e.printStackTrace(); 263 } 264 catch(OutOfRangeException e) 265 { 266 e.printStackTrace(); 267 } 268 } 269 addSegment(final GFFStreamFeature feature, final RangeVector rangesToAdd, final String transcriptName)270 public static void addSegment(final GFFStreamFeature feature, 271 final RangeVector rangesToAdd, 272 final String transcriptName) 273 throws ReadOnlyException, EntryInformationException 274 { 275 // add new ID 276 final Hashtable id_store = feature.getSegmentRangeStore(); 277 String prefix[] = null; 278 Enumeration enum_ids = id_store.keys(); 279 while(enum_ids.hasMoreElements()) 280 { 281 String id = (String) enum_ids.nextElement(); 282 prefix = feature.getPrefix(id, ':'); 283 if(prefix[0] != null) 284 break; 285 } 286 287 // USE PREFIX TO CREATE NEW ID 288 RangeVector rv = (RangeVector)feature.getLocation().getRanges().clone(); 289 for(int i=0; i<rangesToAdd.size(); i++) 290 { 291 final Range range = (Range) rangesToAdd.elementAt(i); 292 final String ID; 293 if(prefix[0] != null) 294 { 295 int auto_num = feature.getAutoNumber(prefix[0], ':'); 296 ID = prefix[0] + ":" + auto_num; 297 feature.getSegmentRangeStore().put(ID, range); 298 } 299 else 300 { 301 String key = feature.getKey().toString(); 302 ID = transcriptName + ":" + key + ":1"; 303 feature.getSegmentRangeStore().put(ID, range); 304 } 305 306 if(!rv.containsRange(range)) 307 rv.add(range); 308 } 309 310 feature.setQualifier(new Qualifier("ID", feature.getSegmentID( rv ))); 311 } 312 313 /** 314 * Used when writing the database entry to a file. This routine 315 * forces lazy-loading qualifier values to be read in full. 316 * @param entry 317 * @param parent 318 */ lazyLoadAll(final Entry entry, final JFrame parent)319 public static void lazyLoadAll(final Entry entry, final JFrame parent) 320 { 321 final List lazySimilarityValues = new Vector(); 322 final List lazyClusterValues = new Vector(); 323 final FeatureVector features = entry.getAllFeatures(); 324 // find any lazy values to be loaded 325 326 for(int i=0; i<features.size(); i++) 327 { 328 QualifierVector qualifiers = features.elementAt(i).getQualifiers(); 329 for(int j=0; j<qualifiers.size(); j++) 330 { 331 Qualifier qualifier = (Qualifier)qualifiers.get(j); 332 if(qualifier instanceof QualifierLazyLoading && 333 !((QualifierLazyLoading)qualifier).isAllLazyValuesLoaded()) 334 { 335 if( ((QualifierLazyLoading)qualifier).getValue(0) instanceof FeatureLocLazyQualifierValue ) 336 lazySimilarityValues.addAll( ((QualifierLazyLoading)qualifier).getLazyValues() ); 337 else if( ((QualifierLazyLoading)qualifier).getValue(0) instanceof ClusterLazyQualifierValue ) 338 { 339 List lazyValues = ((QualifierLazyLoading)qualifier).getLazyValues(); 340 lazyClusterValues.addAll(lazyValues); 341 } 342 343 ((QualifierLazyLoading)qualifier).setForceLoad(true); 344 } 345 } 346 } 347 348 if(lazySimilarityValues.size() > 0 || lazyClusterValues.size() > 0) 349 { 350 int n = JOptionPane.YES_OPTION; 351 if(parent != null) 352 n = JOptionPane.showConfirmDialog(parent, 353 "Load and write to file all qualifers from the database?"+ 354 "\nThis may take a few minutes.", 355 "Load All Data", 356 JOptionPane.YES_NO_OPTION); 357 358 if(n == JOptionPane.YES_OPTION) 359 { 360 if(parent != null) 361 parent.setCursor(new Cursor(Cursor.WAIT_CURSOR)); 362 final DatabaseDocument document = 363 (DatabaseDocument)((DocumentEntry)entry.getEMBLEntry()).getDocument(); 364 365 if(lazySimilarityValues.size() > 0) 366 FeatureLocLazyQualifierValue.bulkRetrieve(lazySimilarityValues,document); 367 368 if(lazyClusterValues.size() > 0) 369 ClusterLazyQualifierValue.setClusterFromValueList(lazyClusterValues, document); 370 371 for(int i=0; i<features.size(); i++) 372 { 373 GFFStreamFeature feature = (GFFStreamFeature)(features.elementAt(i).getEmblFeature()); 374 if(feature.isReadOnly() && 375 feature.getKey().equals("polypeptide_domain") && 376 feature.getChadoLazyFeature() != null) 377 { 378 // load dbxrefs for domains 379 if(feature.getQualifierByName("Dbxref") == null) 380 { 381 DbXRef dbxref = feature.getChadoLazyFeature().getDbXRef(); 382 if(dbxref != null) 383 { 384 String value = dbxref.getDb().getName() + ":" + 385 dbxref.getAccession(); 386 feature.getQualifiers().setQualifier(new Qualifier("Dbxref", value)); 387 388 value= "protein motif:"+value; 389 feature.getQualifiers().setQualifier(new Qualifier("inference", value)); 390 } 391 } 392 } 393 } 394 if(parent != null) 395 parent.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 396 } 397 } 398 } 399 400 /** 401 * Sorts the elements of the vector using a simple O(n^2) selection 402 * sort. 403 */ sort(Vector v)404 private static void sort(Vector v) 405 { 406 int smallest; 407 408 for (int i = 0; i < v.size (); ++i) 409 { 410 //find smallest remaining element 411 smallest = i; 412 for(int j = i + 1 ; j < v.size () ; ++j) 413 { 414 if(((String)v.get(j)).compareTo( (String)v.get(smallest)) < 0) 415 smallest = j; 416 } 417 //exchange smallest and i 418 if (smallest != i) 419 { 420 final String tmp = (String)v.get(i); 421 v.setElementAt (v.get(smallest), i); 422 v.setElementAt (tmp, smallest); 423 } 424 } 425 } 426 427 428 /** 429 * Given a collection of features, determine if these should be 430 * shown or hidden in the Artemis display 431 * @param features 432 */ defineShowHideGeneFeatures(final FeatureVector features)433 public static void defineShowHideGeneFeatures(final FeatureVector features) 434 { 435 final KeyVector keys = 436 features.elementAt(0).getEntry().getEntryInformation().getSortedValidKeys (); 437 final Vector showFeatures = new Vector(); 438 for(int i=0; i<keys.size(); i++) 439 { 440 String keyStr = ((Key)keys.get(i)).getKeyString(); 441 if( !hideFeatures.contains(keyStr) ) 442 showFeatures.add(keyStr); 443 } 444 445 sort(hideFeatures); 446 447 final DefaultListModel showListModel = new DefaultListModel(); 448 for(int i=0; i<showFeatures.size(); i++) 449 showListModel.addElement(showFeatures.get(i)); 450 final JList displayList = new JList(showListModel); 451 452 453 final DefaultListModel hideListModel = new DefaultListModel(); 454 for(int i=0; i<hideFeatures.size(); i++) 455 hideListModel.addElement(hideFeatures.get(i)); 456 final JList hideList = new JList(hideListModel); 457 458 459 final JButton hide_butt = new JButton("HIDE"); 460 hide_butt.addActionListener(new ActionListener() 461 { 462 public void actionPerformed(ActionEvent e) 463 { 464 while(!displayList.isSelectionEmpty()) 465 { 466 final String hideKey = (String)displayList.getSelectedValue(); 467 468 hideFeatures.add(hideKey); 469 if(showFeatures.contains(hideKey)) 470 showFeatures.remove(hideKey); 471 472 sort(hideFeatures); 473 hideListModel.add(hideFeatures.indexOf(hideKey), hideKey); 474 showListModel.removeElement(hideKey); 475 } 476 } 477 }); 478 479 Box bdown = Box.createVerticalBox(); 480 bdown.add(new JLabel("Features Displayed:")); 481 bdown.add(new JScrollPane(displayList)); 482 bdown.add(hide_butt); 483 484 final JPanel hideShowPanel = new JPanel(new BorderLayout()); 485 hideShowPanel.add(bdown, BorderLayout.CENTER); 486 487 488 final JButton show_butt = new JButton("SHOW"); 489 show_butt.addActionListener(new ActionListener() 490 { 491 public void actionPerformed(ActionEvent e) 492 { 493 while(!hideList.isSelectionEmpty()) 494 { 495 final String showKey = (String)hideList.getSelectedValue(); 496 497 if(hideFeatures.contains(showKey)) 498 hideFeatures.remove(showKey); 499 showFeatures.add(showKey); 500 sort(showFeatures); 501 502 showListModel.add(showFeatures.indexOf(showKey), showKey); 503 hideListModel.removeElement(showKey); 504 } 505 } 506 }); 507 508 bdown = Box.createVerticalBox(); 509 bdown.add(Box.createVerticalGlue()); 510 bdown.add(new JLabel("Features Hidden:")); 511 bdown.add(new JScrollPane(hideList)); 512 bdown.add(show_butt); 513 hideShowPanel.add(bdown, BorderLayout.EAST); 514 515 hideShowPanel.add(showObsolete, BorderLayout.SOUTH); 516 517 int select = JOptionPane.showConfirmDialog(null, hideShowPanel, 518 "Gene Model Features Displayed...", 519 JOptionPane.OK_CANCEL_OPTION, 520 JOptionPane.QUESTION_MESSAGE); 521 522 if(select == JOptionPane.CANCEL_OPTION) 523 return; 524 525 showHideGeneFeatures(features); 526 } 527 528 /** 529 * Based on the hidenFeatures and showFeatures set the GFFStreamFeatures 530 * visibility 531 * @param features 532 */ showHideGeneFeatures(final FeatureVector features)533 public static void showHideGeneFeatures(final FeatureVector features) 534 { 535 for(int i=0; i<features.size(); i++) 536 { 537 final Feature feature = features.elementAt(i).getEmblFeature(); 538 539 if(feature instanceof GFFStreamFeature) 540 { 541 if(isObsolete((GFFStreamFeature)feature)) 542 { 543 if(!showObsolete.isSelected()) 544 { 545 ((GFFStreamFeature)feature).setVisible(false); 546 continue; 547 } 548 } 549 550 final String key = feature.getKey().getKeyString(); 551 if(hideFeatures.contains(key)) 552 ((GFFStreamFeature)feature).setVisible(false); 553 else 554 ((GFFStreamFeature)feature).setVisible(true); 555 } 556 } 557 } 558 559 /** 560 * Determine based on the feature given if a feature is hidden 561 * @param key 562 * @return 563 */ isHiddenFeature(final String key)564 public static boolean isHiddenFeature(final String key) 565 { 566 return hideFeatures.contains(key); 567 } 568 569 /** 570 * Test if this feature is obsolete 571 * @param feature 572 * @return 573 */ isObsolete(final uk.ac.sanger.artemis.io.GFFStreamFeature feature)574 public static boolean isObsolete(final uk.ac.sanger.artemis.io.GFFStreamFeature feature) 575 { 576 Qualifier qualifier = feature.getQualifierByName("isObsolete"); 577 if(qualifier == null) 578 return false; 579 580 if( ((String)qualifier.getValues().get(0)).equals("true") ) 581 return true; 582 583 return false; 584 } 585 586 /** 587 * 588 */ duplicateGeneModel(final JFrame frame, final FeatureVector features_to_duplicate, final EntryGroup entry_group)589 public static Vector<ChadoCanonicalGene> duplicateGeneModel(final JFrame frame, 590 final FeatureVector features_to_duplicate, 591 final EntryGroup entry_group) 592 { 593 final Vector<ChadoCanonicalGene> duplicatedGenes = new Vector<ChadoCanonicalGene>(); 594 final Vector<ChadoCanonicalGene> newGenes = new Vector<ChadoCanonicalGene>(); 595 for (int i = 0 ; i < features_to_duplicate.size () ; ++i) 596 { 597 final GFFStreamFeature gffFeature = 598 (GFFStreamFeature)features_to_duplicate.elementAt(i).getEmblFeature(); 599 if(duplicatedGenes.contains(gffFeature.getChadoGene())) 600 continue; 601 602 duplicatedGenes.add(gffFeature.getChadoGene()); 603 604 try 605 { 606 GFFStreamFeature gene = (GFFStreamFeature)gffFeature.getChadoGene().getGene(); 607 uk.ac.sanger.artemis.Feature newGeneFeature = ((uk.ac.sanger.artemis.Feature) 608 gene.getUserData()).duplicate (true); 609 610 final ChadoCanonicalGene chadoGene = gffFeature.getChadoGene(); 611 final ChadoCanonicalGene newchadoGene = new ChadoCanonicalGene(); 612 newGenes.add(newchadoGene); 613 ((GFFStreamFeature)newGeneFeature.getEmblFeature()).setChadoGene(newchadoGene); 614 newchadoGene.setGene(newGeneFeature.getEmblFeature()); 615 616 final List<Feature> transcripts = chadoGene.getTranscripts(); 617 for(int j=0; j<transcripts.size(); j++) // duplicate transcripts and children 618 { 619 final GFFStreamFeature transcript = (GFFStreamFeature)transcripts.get(j); 620 final String transcriptName = getUniqueName(transcript); 621 622 uk.ac.sanger.artemis.Feature newTranscriptFeature = duplicateFeature(transcript, newchadoGene); 623 newchadoGene.addTranscript(newTranscriptFeature.getEmblFeature()); 624 final String newTranscriptName = getUniqueName(newTranscriptFeature.getEmblFeature()); 625 626 List<uk.ac.sanger.artemis.Feature> newFeatures= 627 duplicateFeatures(chadoGene.get3UtrOfTranscript(transcriptName), newchadoGene); 628 for(uk.ac.sanger.artemis.Feature utrFeature: newFeatures) 629 newchadoGene.add3PrimeUtr(newTranscriptName, utrFeature.getEmblFeature()); 630 631 newFeatures = duplicateFeatures(chadoGene.get5UtrOfTranscript(transcriptName), newchadoGene); 632 for(uk.ac.sanger.artemis.Feature utrFeature: newFeatures) 633 newchadoGene.add5PrimeUtr(newTranscriptName, utrFeature.getEmblFeature()); 634 635 newFeatures = duplicateFeatures(chadoGene.getOtherFeaturesOfTranscript(transcriptName), newchadoGene); 636 for(uk.ac.sanger.artemis.Feature otherFeature: newFeatures) 637 newchadoGene.addOtherFeatures(newTranscriptName, otherFeature.getEmblFeature()); 638 639 newFeatures = duplicateFeatures(chadoGene.getSplicedFeaturesOfTranscript(transcriptName), newchadoGene); 640 for(uk.ac.sanger.artemis.Feature splicedFeature: newFeatures) 641 newchadoGene.addSplicedFeatures(newTranscriptName, splicedFeature.getEmblFeature()); 642 643 uk.ac.sanger.artemis.Feature newProtein = 644 duplicateFeature(chadoGene.getProteinOfTranscript(transcriptName), newchadoGene); 645 if(newProtein != null) 646 newchadoGene.addProtein(newTranscriptName, newProtein.getEmblFeature()); 647 } 648 } 649 catch (ReadOnlyException e) {} 650 } 651 652 duplicatedGenes.clear(); 653 return newGenes; 654 } 655 656 duplicateFeatures( final List<Feature> featuresOfTranscript, final ChadoCanonicalGene chadoGene)657 private static List<uk.ac.sanger.artemis.Feature> duplicateFeatures( 658 final List<Feature> featuresOfTranscript, 659 final ChadoCanonicalGene chadoGene) 660 throws ReadOnlyException 661 { 662 final List<uk.ac.sanger.artemis.Feature> newFeatures = 663 new Vector<uk.ac.sanger.artemis.Feature>(); 664 665 if(featuresOfTranscript == null) 666 return newFeatures; 667 668 for(int i=0; i<featuresOfTranscript.size(); i++) 669 newFeatures.add(duplicateFeature( 670 (GFFStreamFeature)featuresOfTranscript.get(i), chadoGene)); 671 return newFeatures; 672 } 673 duplicateFeature( final Feature feature, final ChadoCanonicalGene chadoGene)674 private static uk.ac.sanger.artemis.Feature duplicateFeature( 675 final Feature feature, final ChadoCanonicalGene chadoGene) 676 throws ReadOnlyException 677 { 678 if(feature == null) 679 return null; 680 uk.ac.sanger.artemis.Feature newFeature = 681 ((uk.ac.sanger.artemis.Feature)feature.getUserData()).duplicate(true); 682 ((GFFStreamFeature)newFeature.getEmblFeature()).setChadoGene(chadoGene); 683 if(isHiddenFeature(newFeature.getKey().getKeyString())) 684 ((GFFStreamFeature)newFeature.getEmblFeature()).setVisible(false); 685 return newFeature; 686 } 687 688 /** 689 * Create gene model from base selection 690 * @param frame 691 * @param selection 692 * @param entry_group 693 * @param goto_event_source 694 */ createGeneModel(final JFrame frame, final Selection selection, final EntryGroup entry_group, final GotoEventSource goto_event_source)695 public static void createGeneModel(final JFrame frame, 696 final Selection selection, 697 final EntryGroup entry_group, 698 final GotoEventSource goto_event_source) 699 { 700 if(!SelectionMenu.checkForSelectionRange(frame, selection)) 701 return; 702 final MarkerRange range = selection.getMarkerRange (); 703 final Entry default_entry = entry_group.getDefaultEntry (); 704 705 if (default_entry == null) 706 { 707 new MessageDialog (frame, "There is no default entry"); 708 return; 709 } 710 711 QualifierVector qualifiers = new QualifierVector(); 712 final String uniquename = promptForUniquename(entry_group, 713 range.isForwardMarker()); 714 final Qualifier qualifier = new Qualifier("ID", uniquename); 715 qualifiers.add(qualifier); 716 717 try 718 { 719 final FeatureVector newFeatures = new FeatureVector(); 720 final Location new_location = range.createLocation (); 721 final Key key = new Key("gene"); 722 final uk.ac.sanger.artemis.Feature geneFeature = 723 default_entry.createFeature(key, new_location, qualifiers); 724 newFeatures.add(geneFeature); 725 726 final ChadoCanonicalGene chadoGene = new ChadoCanonicalGene(); 727 chadoGene.setGene(geneFeature.getEmblFeature()); 728 ((uk.ac.sanger.artemis.io.GFFStreamFeature) 729 (geneFeature.getEmblFeature())).setChadoGene(chadoGene); 730 731 // create transcript 732 uk.ac.sanger.artemis.Feature transcript = 733 GeneViewerPanel.createTranscript(chadoGene, entry_group); 734 newFeatures.add(transcript); 735 ((uk.ac.sanger.artemis.io.GFFStreamFeature) 736 (transcript.getEmblFeature())).setChadoGene(chadoGene); 737 final String transcriptId = 738 (String)transcript.getQualifierByName("ID").getValues().get(0); 739 740 // add exon 741 GFFStreamFeature exonFeature = 742 GeneViewerPanel.addExonFeature(chadoGene, entry_group, 743 null, new_location.getTotalRange(), transcriptId, selection, 744 new Key(DatabaseDocument.EXONMODEL), null); 745 746 // add protein 747 uk.ac.sanger.artemis.Feature polypep = 748 GeneViewerPanel.addProteinFeature(chadoGene, entry_group, transcriptId, transcript); 749 newFeatures.add(polypep); 750 751 // add inferred CDS 752 if(DatabaseDocument.CHADO_INFER_CDS) 753 DatabaseInferredFeature.createFeature(transcriptId, exonFeature, 754 chadoGene, entry_group.getDefaultEntry()); 755 756 showHideGeneFeatures(newFeatures); 757 selection.clear(); 758 selection.add(polypep); 759 760 EditMenu.editSelectedFeatures(entry_group, selection, 761 goto_event_source, polypep, null, null); 762 } 763 catch(ReadOnlyException e) 764 { 765 // TODO Auto-generated catch block 766 e.printStackTrace(); 767 } 768 catch(EntryInformationException e) 769 { 770 // TODO Auto-generated catch block 771 e.printStackTrace(); 772 } 773 catch(OutOfRangeException e) 774 { 775 // TODO Auto-generated catch block 776 e.printStackTrace(); 777 } 778 } 779 780 /** 781 * Prompt the user for an ID 782 * @return 783 */ promptForUniquename(final EntryGroup entry_group, final boolean is_forward)784 public static String promptForUniquename(final EntryGroup entry_group, 785 final boolean is_forward) 786 { 787 final Entry default_entry = entry_group.getDefaultEntry (); 788 String id = null; 789 790 if(default_entry.getEMBLEntry() instanceof 791 uk.ac.sanger.artemis.io.DatabaseDocumentEntry || 792 default_entry.getEMBLEntry() instanceof 793 uk.ac.sanger.artemis.io.GFFDocumentEntry) 794 { 795 while(id == null || 796 id.equals("") || 797 id.equals("to_be_set")) 798 { 799 String msg = "Provide a unique ID "; 800 801 if(!is_forward) 802 msg = msg + "for reverse strand : "; 803 else 804 msg = msg + ": "; 805 806 id = JOptionPane.showInputDialog(null, 807 msg, 808 "ID missing ", 809 JOptionPane.QUESTION_MESSAGE).trim(); 810 811 if(!isUniqueID(entry_group, id)) 812 { 813 JOptionPane.showMessageDialog(null, 814 "ID "+id+" not unique.\nEnter a unique ID.", 815 "ID Not Unique", 816 JOptionPane.WARNING_MESSAGE); 817 id = null; 818 } 819 } 820 } 821 return id; 822 } 823 824 /** 825 * Prompt the user for an ID and provide a default automated ID 826 * based on the range. 827 * @param entry_group 828 * @param is_forward 829 * @param range 830 * @return 831 */ promptForUniquename(final EntryGroup entry_group, final boolean is_forward, final Range range)832 public static String promptForUniquename(final EntryGroup entry_group, 833 final boolean is_forward, 834 final Range range) 835 { 836 final Entry default_entry = entry_group.getDefaultEntry (); 837 String id = null; 838 839 if(default_entry.getEMBLEntry() instanceof 840 uk.ac.sanger.artemis.io.DatabaseDocumentEntry) 841 { 842 843 while(id == null || 844 id.equals("") || 845 id.equals("to_be_set")) 846 { 847 String msg = "Provide a unique ID "; 848 849 if(!is_forward) 850 msg = msg + "for reverse strand : "; 851 else 852 msg = msg + ": "; 853 854 855 id = JOptionPane.showInputDialog(null, msg, 856 default_entry.getName()+":"+ 857 range.getStart()+".."+ 858 range.getEnd()); 859 860 if(!isUniqueID(entry_group, id)) 861 { 862 JOptionPane.showMessageDialog(null, 863 "ID "+id+" not unique.\nEnter a unique ID.", 864 "ID Not Unique", 865 JOptionPane.WARNING_MESSAGE); 866 id = null; 867 } 868 } 869 } 870 return id; 871 } 872 873 874 /** 875 * Test to ensure ID (chado uniquename) is unique. 876 * @param entry_group 877 * @param id 878 * @return 879 */ isUniqueID(final EntryGroup entry_group, final String id)880 private static boolean isUniqueID(final EntryGroup entry_group, 881 final String id) 882 { 883 final FeaturePredicate predicate = 884 new FeatureKeyQualifierPredicate(null, "ID", id, 885 false, true); 886 final FeatureVector features = entry_group.getAllFeatures(); 887 for(int i=0; i<features.size(); i++) 888 { 889 uk.ac.sanger.artemis.Feature feature = features.elementAt(i); 890 if(predicate.testPredicate(feature)) 891 return false; 892 893 } 894 return true; 895 } 896 897 /** 898 * Given an group of entries determine if they contain a database entry 899 * @param entryGroup 900 * @return 901 */ isDatabaseEntry(final EntryGroup entryGroup)902 public static boolean isDatabaseEntry(final EntryGroup entryGroup) 903 { 904 final EntryVector entries = entryGroup.getActiveEntries(); 905 906 for(int i=0; i<entries.size(); i++) 907 { 908 if( entries.elementAt(i).getEMBLEntry() instanceof DatabaseDocumentEntry ) 909 return true; 910 } 911 return false; 912 } 913 914 /** 915 * Given an group of entries determine if they contain a GFF entry 916 * @param entryGroup 917 * @return 918 */ isGFFEntry(final EntryGroup entryGroup)919 public static boolean isGFFEntry(final EntryGroup entryGroup) 920 { 921 final EntryVector entries = entryGroup.getActiveEntries(); 922 923 for(int i=0; i<entries.size(); i++) 924 { 925 if( entries.elementAt(i).getEMBLEntry() instanceof GFFDocumentEntry ) 926 return true; 927 } 928 return false; 929 } 930 931 932 /** 933 * Given a feature determine if it belongs to a database entry 934 * @param entryGroup 935 * @return 936 */ isDatabaseEntry(final Feature feature)937 public static boolean isDatabaseEntry(final Feature feature) 938 { 939 if( feature.getEntry() instanceof DatabaseDocumentEntry && 940 ((GFFStreamFeature)feature).getDocumentEntry().getDocument() instanceof DatabaseDocument) 941 return true; 942 943 return false; 944 } 945 946 deleteFeature(uk.ac.sanger.artemis.Feature feature)947 private static void deleteFeature(uk.ac.sanger.artemis.Feature feature) 948 throws ReadOnlyException 949 { 950 if(feature != null && feature.getEntry() != null) 951 feature.removeFromEntry(); 952 } 953 deleteAllFeature(uk.ac.sanger.artemis.Feature feature, final ChadoCanonicalGene chado_gene)954 public static void deleteAllFeature(uk.ac.sanger.artemis.Feature feature, 955 final ChadoCanonicalGene chado_gene) throws ReadOnlyException 956 { 957 deleteAllFeature(feature, chado_gene, true); 958 } 959 960 /** 961 * Delete feature and children in a chado gene model 962 * @param feature 963 * @param chado_gene 964 * @throws ReadOnlyException 965 */ deleteAllFeature(uk.ac.sanger.artemis.Feature feature, final ChadoCanonicalGene chado_gene, final boolean updateChadoCanonicalGene)966 public static void deleteAllFeature(uk.ac.sanger.artemis.Feature feature, 967 final ChadoCanonicalGene chado_gene, final boolean updateChadoCanonicalGene) throws ReadOnlyException 968 { 969 Set<Feature> children = chado_gene.getChildren(feature.getEmblFeature()); 970 deleteFeature(feature); 971 if(updateChadoCanonicalGene) 972 chado_gene.deleteFeature(feature.getEmblFeature()); 973 974 Feature embl_feature; 975 Iterator<Feature> it = children.iterator(); 976 977 while(it.hasNext()) 978 { 979 embl_feature = it.next(); 980 deleteFeature((uk.ac.sanger.artemis.Feature) embl_feature.getUserData()); 981 if(updateChadoCanonicalGene) 982 chado_gene.deleteFeature(embl_feature); 983 } 984 } 985 986 /** 987 * Check gene model strands for any inconsistencies 988 * @param chado_gene 989 * @return true is gene model ranges are correct 990 */ isStrandOK(final ChadoCanonicalGene chado_gene)991 public static boolean isStrandOK(final ChadoCanonicalGene chado_gene) 992 { 993 boolean isRev = chado_gene.getGene().getLocation().isComplement(); 994 final List<Feature> transcripts = chado_gene.getTranscripts(); 995 996 for(int i=0; i<transcripts.size(); i++) 997 { 998 final Feature transcript = (Feature)transcripts.get(i); 999 1000 if(isRev ^ transcript.getLocation().isComplement()) 1001 return false; 1002 1003 final Feature protein = 1004 chado_gene.getProteinOfTranscript(GeneUtils.getUniqueName(transcript)); 1005 if(protein != null && (isRev ^ protein.getLocation().isComplement())) 1006 return false; 1007 1008 final Set<Feature> children = chado_gene.getChildren(transcript); 1009 final Iterator<Feature> it = children.iterator(); 1010 while(it.hasNext()) 1011 { 1012 final Feature feature = it.next(); 1013 if(isRev ^ feature.getLocation().isComplement()) 1014 return false; 1015 } 1016 } 1017 return true; 1018 } 1019 1020 /** 1021 * Check gene model boundaries for any inconsistencies 1022 * @param chado_gene 1023 * @return 0 - if consisent 1024 * 1 - if transcript start or end is outside gene range 1025 * 2 - if child feature of a transcript is outside the transcript range 1026 * 3 - if the span of the children features does not match start and end of the transcript 1027 * 4 - if the protein range does not match CDS 1028 * 5 - if the gene range does not match the largest transcript range 1029 */ isBoundaryOK(final ChadoCanonicalGene chado_gene)1030 public static int isBoundaryOK(final ChadoCanonicalGene chado_gene) 1031 { 1032 final Range geneRange = chado_gene.getGene().getLocation().getTotalRange(); 1033 final List<Feature> transcripts = chado_gene.getTranscripts(); 1034 int geneStart = Integer.MAX_VALUE; 1035 int geneEnd = -1; 1036 1037 for(Feature transcript: transcripts) 1038 { 1039 final Range transcriptRange = transcript.getLocation().getTotalRange(); 1040 int transcriptStart = Integer.MAX_VALUE; 1041 int transcriptEnd = -1; 1042 int ppStart = Integer.MAX_VALUE; 1043 int ppEnd = -1; 1044 1045 if(transcriptRange.getStart() < geneRange.getStart() || 1046 transcriptRange.getEnd() > geneRange.getEnd()) 1047 return 1; 1048 1049 if(transcriptRange.getStart() < geneStart) 1050 geneStart = transcriptRange.getStart(); 1051 if(transcriptRange.getEnd() > geneEnd) 1052 geneEnd = transcriptRange.getEnd(); 1053 1054 final Feature protein = 1055 chado_gene.getProteinOfTranscript(GeneUtils.getUniqueName(transcript)); 1056 String proteinName = null; 1057 if(protein != null) 1058 proteinName = GeneUtils.getUniqueName(protein); 1059 1060 final Set<Feature> children = chado_gene.getChildren(transcript); 1061 final Iterator<Feature> it = children.iterator(); 1062 while(it.hasNext()) 1063 { 1064 final Feature feature = it.next(); 1065 final Range childRange = feature.getLocation().getTotalRange(); 1066 if(childRange.getStart() < transcriptRange.getStart() || 1067 childRange.getEnd() > transcriptRange.getEnd()) 1068 return 2; 1069 1070 if(proteinName != null && 1071 GeneUtils.getUniqueName(feature).equals(proteinName)) 1072 continue; 1073 1074 if(childRange.getStart() < transcriptStart) 1075 transcriptStart = childRange.getStart(); 1076 if(childRange.getEnd() > transcriptEnd ) 1077 transcriptEnd = childRange.getEnd(); 1078 1079 String keyStr = feature.getKey().getKeyString(); 1080 if( (DatabaseDocument.CHADO_INFER_CDS && keyStr.equals("CDS")) || 1081 (!DatabaseDocument.CHADO_INFER_CDS && keyStr.equals(DatabaseDocument.EXONMODEL)) || 1082 feature.getKey().equals("pseudogenic_exon")) 1083 { 1084 if(childRange.getStart() < ppStart) 1085 ppStart = childRange.getStart(); 1086 if(childRange.getEnd() > ppEnd ) 1087 ppEnd = childRange.getEnd(); 1088 } 1089 } 1090 1091 if((transcriptRange.getStart() != transcriptStart && transcriptStart < Integer.MAX_VALUE) || 1092 (transcriptRange.getEnd() != transcriptEnd && transcriptEnd > -1)) 1093 return 3; 1094 1095 if(protein != null) 1096 { 1097 final Range proteinRange = protein.getLocation().getTotalRange(); 1098 if((proteinRange.getStart() != ppStart && ppStart < Integer.MAX_VALUE) || 1099 (proteinRange.getEnd() != ppEnd && ppEnd > -1)) 1100 return 4; 1101 } 1102 } 1103 1104 // check gene range 1105 if((geneRange.getStart() != geneStart && geneStart < Integer.MAX_VALUE) || 1106 (geneRange.getEnd() != geneEnd && geneEnd > -1)) 1107 return 5; 1108 1109 return 0; 1110 } 1111 checkGeneBoundary(final ChadoCanonicalGene chado_gene)1112 public static void checkGeneBoundary(final ChadoCanonicalGene chado_gene) 1113 { 1114 checkGeneBoundary(chado_gene, true); 1115 } 1116 checkTranscriptBoundary( final uk.ac.sanger.artemis.Feature transcript, final ChadoCanonicalGene chado_gene)1117 protected static Range checkTranscriptBoundary( 1118 final uk.ac.sanger.artemis.Feature transcript, 1119 final ChadoCanonicalGene chado_gene) 1120 { 1121 return checkTranscriptBoundary(transcript, chado_gene, true); 1122 } 1123 1124 /** 1125 * Adjust transcript and gene boundaries 1126 * @param chado_gene 1127 */ checkGeneBoundary(final ChadoCanonicalGene chado_gene, final boolean changeEmblFeature)1128 public static void checkGeneBoundary(final ChadoCanonicalGene chado_gene, final boolean changeEmblFeature) 1129 { 1130 final List<Feature> transcripts = chado_gene.getTranscripts(); 1131 int gene_start = Integer.MAX_VALUE; 1132 int gene_end = -1; 1133 1134 Range range; 1135 for(Feature transcript: transcripts) 1136 { 1137 range = checkTranscriptBoundary( 1138 (uk.ac.sanger.artemis.Feature)transcript.getUserData(), chado_gene, changeEmblFeature); 1139 if(range != null && range.getStart() < gene_start) 1140 gene_start = range.getStart(); 1141 if(range != null && range.getEnd() > gene_end) 1142 gene_end = range.getEnd(); 1143 } 1144 1145 if(gene_end == -1 && gene_start == Integer.MAX_VALUE) 1146 return; 1147 1148 setLocation(chado_gene.getGene(), gene_start, gene_end, changeEmblFeature); 1149 } 1150 1151 /** 1152 * Check and adjust transcript boundary 1153 * @param transcript 1154 * @param chado_gene 1155 * @param changeEmblFeature 1156 * @return 1157 */ checkTranscriptBoundary( final uk.ac.sanger.artemis.Feature transcript, final ChadoCanonicalGene chado_gene, final boolean changeEmblFeature)1158 protected static Range checkTranscriptBoundary( 1159 final uk.ac.sanger.artemis.Feature transcript, 1160 final ChadoCanonicalGene chado_gene, 1161 final boolean changeEmblFeature) 1162 { 1163 final List transcripts = chado_gene.getTranscripts(); 1164 1165 if(transcripts.contains(transcript.getEmblFeature())) 1166 { 1167 checkProteinBoundary(transcript.getEmblFeature(), chado_gene, changeEmblFeature); 1168 1169 final Set children = chado_gene.getChildren(transcript.getEmblFeature()); 1170 int transcript_start = Integer.MAX_VALUE; 1171 int transcript_end = -1; 1172 1173 final Iterator it = children.iterator(); 1174 while(it.hasNext()) 1175 { 1176 final Feature feature = (Feature) it.next(); 1177 final Range range = feature.getLocation().getTotalRange(); 1178 if(range.getStart() < transcript_start) 1179 transcript_start = range.getStart(); 1180 if(range.getEnd() > transcript_end) 1181 transcript_end = range.getEnd(); 1182 } 1183 1184 if(transcript_start == Integer.MAX_VALUE || 1185 transcript_end == -1) 1186 return null; 1187 1188 return setLocation(transcript.getEmblFeature(), 1189 transcript_start, transcript_end, changeEmblFeature); 1190 } 1191 else 1192 JOptionPane.showMessageDialog(null, 1193 "Select a single transcript and try again.", "Transcript Selection", 1194 JOptionPane.ERROR_MESSAGE); 1195 return null; 1196 } 1197 1198 /** 1199 * Check and adjust protein boundary 1200 * @param transcript 1201 * @param chado_gene 1202 */ checkProteinBoundary(final Feature transcript, final ChadoCanonicalGene chado_gene, final boolean changeEmblFeature)1203 private static void checkProteinBoundary(final Feature transcript, 1204 final ChadoCanonicalGene chado_gene, 1205 final boolean changeEmblFeature) 1206 { 1207 final String transcriptName = getUniqueName(transcript); 1208 final Feature protein = chado_gene.getProteinOfTranscript(transcriptName); 1209 if(protein == null) 1210 return; 1211 1212 int pp_start = Integer.MAX_VALUE; 1213 int pp_end = -1; 1214 1215 final List<Feature> dnaFeatures = new Vector<Feature>(); 1216 /* if(chado_gene.get3UtrOfTranscript(transcriptName) != null) 1217 dnaFeatures.addAll(chado_gene.get3UtrOfTranscript(transcriptName)); 1218 if(chado_gene.get5UtrOfTranscript(transcriptName) != null) 1219 dnaFeatures.addAll(chado_gene.get5UtrOfTranscript(transcriptName));*/ 1220 1221 List<Feature> exons; 1222 if(DatabaseDocument.CHADO_INFER_CDS) 1223 exons = chado_gene.getSpliceSitesOfTranscript(transcriptName, "CDS"); 1224 else 1225 exons = chado_gene.getSpliceSitesOfTranscript(transcriptName, DatabaseDocument.EXONMODEL); 1226 if(exons != null) 1227 dnaFeatures.addAll(exons); 1228 1229 exons = chado_gene.getSpliceSitesOfTranscript(transcriptName, "pseudogenic_exon"); 1230 if(exons != null) 1231 dnaFeatures.addAll(exons); 1232 1233 for(Feature dnaFeature: dnaFeatures) 1234 { 1235 final Range range = dnaFeature.getLocation().getTotalRange(); 1236 if(range.getStart() < pp_start) 1237 pp_start = range.getStart(); 1238 if(range.getEnd() > pp_end) 1239 pp_end = range.getEnd(); 1240 } 1241 1242 if(pp_start == Integer.MAX_VALUE || pp_end == -1) 1243 return; 1244 1245 setLocation(protein, pp_start, pp_end, changeEmblFeature); 1246 } 1247 1248 /** 1249 * For a feature propagate the uniquename as the prefix for 1250 * the associated children. 1251 * @param gene 1252 * @param newName 1253 * @param children 1254 */ propagateId(final GFFStreamFeature feature, final String newName, final Set children)1255 public static void propagateId(final GFFStreamFeature feature, 1256 final String newName, 1257 final Set children) 1258 { 1259 final ChadoCanonicalGene gene = feature.getChadoGene(); 1260 final Iterator it = children.iterator(); 1261 while(it.hasNext()) 1262 { 1263 final GFFStreamFeature child = (GFFStreamFeature)it.next(); 1264 final Hashtable segmentHash = child.getSegmentRangeStore(); 1265 1266 final String oldId = getUniqueName(child); 1267 1268 final Set childrenOfChild = gene.getChildren(child); 1269 int index = oldId.lastIndexOf('.'); 1270 1271 if(index == -1) 1272 index = oldId.indexOf(':'); 1273 1274 if(index > -1) 1275 { 1276 final String newId; 1277 if( segmentHash != null && 1278 ( segmentHash.size() > 1 || 1279 child.getKey().getKeyString().equals(DatabaseDocument.EXONMODEL))) 1280 { 1281 final Set idKeys = segmentHash.keySet(); 1282 final Hashtable newSegmentHash = new Hashtable(idKeys.size()); 1283 final Iterator itKeys = idKeys.iterator(); 1284 final Hashtable newIdMapToOldId = new Hashtable(idKeys.size()); 1285 while(itKeys.hasNext()) 1286 { 1287 String oldKey = (String)itKeys.next(); 1288 index = oldKey.lastIndexOf('.'); 1289 if(index == -1) 1290 index = oldKey.indexOf(':'); 1291 final String newKey = newName + oldKey.substring(index); 1292 Object range = segmentHash.get(oldKey); 1293 1294 newSegmentHash.put(newKey, range); 1295 newIdMapToOldId.put(newKey, oldKey); 1296 } 1297 child.setSegmentRangeStore(newSegmentHash); 1298 child.setNewIdMapToOldId(newIdMapToOldId); 1299 newId = child.getSegmentID(child.getLocation().getRanges()); 1300 } 1301 else 1302 newId = newName + oldId.substring(index); 1303 try 1304 { 1305 ((uk.ac.sanger.artemis.Feature) child.getUserData()) 1306 .setQualifier(new Qualifier("ID", newId)); 1307 gene.updateUniqueName(oldId, newId, childrenOfChild); 1308 } 1309 catch(ReadOnlyException e) 1310 { 1311 e.printStackTrace(); 1312 } 1313 catch(EntryInformationException e) 1314 { 1315 e.printStackTrace(); 1316 } 1317 } 1318 } 1319 } 1320 1321 /** 1322 * Fix parent (Parent and Derives_from) qualifiers. Used when the 1323 * uniqueName of the parent has been changed. 1324 * @param oldName 1325 * @param newName 1326 * @param children 1327 */ fixParentQualifier(final String oldName, final String newName, final Set children)1328 public static void fixParentQualifier(final String oldName, 1329 final String newName, 1330 final Set children) 1331 { 1332 final Iterator it = children.iterator(); 1333 while(it.hasNext()) 1334 { 1335 Feature child = (Feature)it.next(); 1336 QualifierVector qualifiers = child.getQualifiers(); 1337 if( qualifiers.getQualifierByName("Parent") != null && 1338 ((String)(qualifiers.getQualifierByName("Parent").getValues().get(0))).equals(oldName) ) 1339 { 1340 qualifiers.removeQualifierByName("Parent"); 1341 qualifiers.setQualifier(new Qualifier("Parent", newName)); 1342 } 1343 else if( qualifiers.getQualifierByName("Derives_from") != null && 1344 ((String)(qualifiers.getQualifierByName("Derives_from").getValues().get(0))).equals(oldName) ) 1345 { 1346 qualifiers.removeQualifierByName("Derives_from"); 1347 qualifiers.setQualifier(new Qualifier("Derives_from", newName)); 1348 } 1349 } 1350 } 1351 1352 /** 1353 * Converts a gene to pseudogene or vice-versa 1354 * @param chado_gene 1355 * @throws EntryInformationException 1356 * @throws ReadOnlyException 1357 * @throws OutOfRangeException 1358 */ convertPseudo(final ChadoCanonicalGene chado_gene)1359 public static void convertPseudo(final ChadoCanonicalGene chado_gene) 1360 throws ReadOnlyException, EntryInformationException, OutOfRangeException 1361 { 1362 final Key geneKey = chado_gene.getGene().getKey(); 1363 1364 boolean convertToPseudogene = false; 1365 1366 uk.ac.sanger.artemis.Feature gene = (uk.ac.sanger.artemis.Feature)chado_gene.getGene().getUserData(); 1367 if(geneKey.equals("gene")) 1368 { 1369 gene.set(new Key("pseudogene"), gene.getLocation(), gene.getQualifiers()); 1370 convertToPseudogene = true; 1371 } 1372 else if(geneKey.equals("pseudogene")) 1373 gene.set(new Key("gene"), gene.getLocation(), gene.getQualifiers()); 1374 else 1375 return; 1376 1377 final List transcripts = chado_gene.getTranscripts(); 1378 for(int i=0; i<transcripts.size(); i++) 1379 { 1380 final uk.ac.sanger.artemis.Feature transcript = ( 1381 uk.ac.sanger.artemis.Feature)((Feature)transcripts.get(i)).getUserData(); 1382 final String transcriptName = getUniqueName(transcript.getEmblFeature()); 1383 final List exons; 1384 if(convertToPseudogene) 1385 { 1386 exons = chado_gene.getSpliceSitesOfTranscript(transcriptName, 1387 DatabaseDocument.EXONMODEL); 1388 transcript.set(new Key("pseudogenic_transcript"), transcript.getLocation(), 1389 transcript.getQualifiers()); 1390 } 1391 else 1392 { 1393 exons = chado_gene.getSpliceSitesOfTranscript(transcriptName, 1394 "pseudogenic_exon"); 1395 transcript.set(new Key(DatabaseDocument.TRANSCRIPT), transcript.getLocation(), transcript.getQualifiers()); 1396 } 1397 1398 if(exons == null) 1399 continue; 1400 1401 for(int j=0; j<exons.size(); j++) 1402 { 1403 final uk.ac.sanger.artemis.Feature exon = (uk.ac.sanger.artemis.Feature)((Feature)exons.get(j)).getUserData(); 1404 exon.resetColour(); 1405 if(convertToPseudogene) 1406 exon.set(new Key("pseudogenic_exon"), exon.getLocation(), exon.getQualifiers()); 1407 else 1408 exon.set(new Key(DatabaseDocument.EXONMODEL), exon.getLocation(), exon.getQualifiers()); 1409 } 1410 } 1411 } 1412 setLocation(final Feature f, final int start, final int end, final boolean changeEmblFeature)1413 private static Range setLocation(final Feature f, 1414 final int start, 1415 final int end, 1416 final boolean changeEmblFeature) 1417 { 1418 try 1419 { 1420 final RangeVector ranges = new RangeVector(); 1421 final Range range = new Range(start, end); 1422 ranges.add(range); 1423 1424 final Location new_location = new Location(ranges, 1425 f.getLocation().isComplement()); 1426 1427 if(changeEmblFeature) 1428 f.setLocation(new_location); 1429 else 1430 ((uk.ac.sanger.artemis.Feature)f.getUserData()).setLocation(new_location); 1431 return range; 1432 } 1433 catch (OutOfRangeException e) 1434 { 1435 // TODO Auto-generated catch block 1436 e.printStackTrace(); 1437 } 1438 catch (ReadOnlyException e) 1439 { 1440 // TODO Auto-generated catch block 1441 e.printStackTrace(); 1442 } 1443 return null; 1444 } 1445 getUniqueName(final Feature feature)1446 public static String getUniqueName(final Feature feature) 1447 { 1448 try 1449 { 1450 return (String)feature.getQualifierByName("ID").getValues().get(0); 1451 } 1452 catch(InvalidRelationException e) 1453 { 1454 e.printStackTrace(); 1455 } 1456 return null; 1457 } 1458 1459 /** 1460 * Return an array on non-coding transcripts 1461 * @return 1462 */ getNonCodingTranscripts()1463 public static String[] getNonCodingTranscripts() 1464 { 1465 return nonCodingTranscripts; 1466 } 1467 1468 /** 1469 * Test if the key given is a non-coding transcript key 1470 * @param key 1471 * @return 1472 */ isNonCodingTranscripts(final Key key)1473 public static boolean isNonCodingTranscripts(final Key key) 1474 { 1475 for(int i=0; i<nonCodingTranscripts.length; i++) 1476 if(nonCodingTranscripts[i].equals(key.getKeyString())) 1477 return true; 1478 return false; 1479 } 1480 deriveResidues(final GFFStreamFeature gffFeature)1481 public static String deriveResidues(final GFFStreamFeature gffFeature) 1482 { 1483 final ChadoCanonicalGene chadoGene = gffFeature.getChadoGene(); 1484 1485 boolean isProteinFeature = 1486 ((uk.ac.sanger.artemis.Feature)gffFeature.getUserData()).isProteinFeature(); 1487 1488 String residues = null; 1489 try 1490 { 1491 String transcriptName = 1492 chadoGene.getTranscriptFromName(GeneUtils.getUniqueName(gffFeature)); 1493 1494 List<Feature> splicedFeatures = 1495 chadoGene.getSplicedFeaturesOfTranscript(transcriptName); 1496 for (Feature emblFeature: splicedFeatures) 1497 { 1498 if (emblFeature.getKey().getKeyString().equals( 1499 DatabaseDocument.EXONMODEL) || 1500 emblFeature.getKey().getKeyString().equals("pseudogenic_exon")) 1501 { 1502 uk.ac.sanger.artemis.Feature f = 1503 (uk.ac.sanger.artemis.Feature) emblFeature.getUserData(); 1504 if (!isProteinFeature) 1505 residues = f.getTranslationBases(); 1506 else 1507 residues = f.getTranslation().toString(); 1508 } 1509 } 1510 } 1511 catch (Exception e){ } 1512 1513 return residues; 1514 } 1515 getFeatureForUpdatingResidues( final GFFStreamFeature gffFeature)1516 public static FeatureForUpdatingResidues getFeatureForUpdatingResidues( 1517 final GFFStreamFeature gffFeature) 1518 { 1519 if(!isFeatureToUpdateResidues(gffFeature.getKey().getKeyString())) 1520 return null; 1521 String residues = deriveResidues(gffFeature); 1522 if(residues == null) 1523 return null; 1524 final FeatureForUpdatingResidues chadoFeature = new FeatureForUpdatingResidues(); 1525 chadoFeature.setStartBase(0); 1526 chadoFeature.setLength(residues.length()); 1527 chadoFeature.setNewSubSequence(residues); 1528 chadoFeature.setResidueUpdate(true); 1529 1530 if(gffFeature.getQualifierByName("feature_id") != null) 1531 chadoFeature.setFeatureId( Integer.parseInt( (String) 1532 gffFeature.getQualifierByName("feature_id").getValues().get(0)) ); 1533 else 1534 { 1535 chadoFeature.setFeatureId(-1); 1536 chadoFeature.setUniqueName(getUniqueName(gffFeature)); 1537 } 1538 chadoFeature.setSeqLen(residues.length()); 1539 return chadoFeature; 1540 } 1541 1542 /** 1543 * Look at the sequence_update_features property in the options 1544 * file to see if this is a feature to update residues for. 1545 * @param keyStr 1546 * @return 1547 */ isFeatureToUpdateResidues(final String keyStr)1548 public static boolean isFeatureToUpdateResidues(final String keyStr) 1549 { 1550 if(featuresToUpdateResidues == null) 1551 return false; 1552 1553 return featuresToUpdateResidues.contains(keyStr); 1554 } 1555 main(String args[])1556 public static void main(String args[]) 1557 { 1558 GeneUtils.defineShowHideGeneFeatures(new FeatureVector()); 1559 } 1560 } 1561