001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.program.blast2html; 023 024import java.io.PrintWriter; 025import java.util.Arrays; 026import java.util.List; 027import java.util.Properties; 028 029/** 030 * Renders HTML version of blast-like output.<p> 031 * 032 * Makes an assumption that the gap character is '-', 033 * should parameterize. 034 * 035 * 036 * Primary author - 037 * Colin Hardman (CAT) 038 * Other authors - 039 * Tim Dilks (CAT) 040 * Simon Brocklehurst (CAT) 041 * Stuart Johnston (CAT) 042 * Lawerence Bower (CAT) 043 * Derek Crockford (CAT) 044 * Neil Benn (CAT) 045 * 046 * Copyright 2001 Cambridge Antibody Technology Group plc. 047 * 048 * This code released to the biojava project, May 2001 049 * under the LGPL license. 050 * 051 * @author Cambridge Antibody Technology Group plc 052 * @author Greg Cox 053 * @version 1.0 054 */ 055public class HTMLRenderer { 056 057 private StringBuffer align = new StringBuffer(); 058 private StringBuffer alignMarkUp1 = new StringBuffer(); 059 private StringBuffer alignMarkUp2 = new StringBuffer(); 060 061 private PrintWriter out = null; 062 private String oStyleDef; 063 private StringBuffer pcDataBuffer = new StringBuffer( 80 ); 064 065 private boolean tAlternateSummary = false; 066 private int iSummaryCount =0; 067 068 private boolean tNeedComma = false; 069 070 /** 071 * The width, in characters, of the sequence alignments 072 */ 073 private int iAlignLen = 50; 074 075 private List oURLGeneratorList = null; 076 private DatabaseURLGenerator oFirstURLGenerator = null; 077 078 private AlignmentMarker oAlignmentMarker; 079 080 private static String oJavaScriptDef 081 = "<script language=\"JavaScript\">\nfunction setStatus(msgStr) { \n status=msgStr;\n document.retVal = true;\n}\n</script>"; 082 083 private char[] padding = new char[100]; 084 085 { 086 Arrays.fill( padding, 087 0, 088 100, 089 ' ' ); 090 } 091 092 private Properties oOptions = null; 093 094 /** 095 * Flag to detect if HTML output was empty. 096 */ 097 private boolean wasEmpty = true; 098 099 /** 100 * Creates an HTMLRenderer, that outputs the HTML to the specified 101 * PrintWriter. <p> 102 * 103 * The style definition is expected to defines the following styles 104 * <UL> 105 * <LI> footer 106 * <LI> alignment 107 * <LI> dbRetrieve 108 * <LI> titleLevel1 109 * <LI> titleLevel1Sub 110 * <LI> titleLevel2 111 * <LI> titleLevel3 112 * <LI> titleLevel3Sub 113 * <LI> titleLevel4 114 * <LI> summaryBodyLineOdd 115 * <LI> summaryBodyLineEven 116 * </UL 117 * 118 * The Javascript function setStatus overrides status text for some links. 119 * 120 * The URLGeneratorFactory provides a list of objects that can convert a 121 * database ID into a URL for fetching the entry. Obviously this requires 122 * the ID to be parsed correctly.<B> 123 * These URL's are used in two places, in the summary and detail sections. 124 * The first URLGenerator is used for the summary, and all for the detail. 125 * 126 * 127 * @param poPrintWriter - the output stream to write the HTML to. 128 * @param poStyleDef - definition of styles, if null uses hard coded. 129 * @param piAlignmentWidth width in characters of the alignment regions 130 * of output 131 * @param poFactory <code>URLGeneratorFactory</code> provides an array of 132 * <code>DatabaseURLGenerator</code>s, null for no links 133 * @param poAlignmentMarker - for configurable markup of alignments, 134 * for no markup use null. 135 * @param poOptions properties of 136 */ 137 public HTMLRenderer( PrintWriter poPrintWriter, 138 String poStyleDef, 139 int piAlignmentWidth, 140 URLGeneratorFactory poFactory, 141 AlignmentMarker poAlignmentMarker, 142 Properties poOptions ) { 143 144 oOptions = poOptions; 145 146 if ( poFactory != null ) { 147 148 oURLGeneratorList = poFactory.getDatabaseURLGenerators(); 149 if ( !oURLGeneratorList.isEmpty() ) { 150 oFirstURLGenerator 151 = (DatabaseURLGenerator) oURLGeneratorList.get( 0 ); 152 } 153 } 154 155 if ( piAlignmentWidth <= 0 ) { 156 throw new IllegalArgumentException 157 ( "Alignment length must be > 0, not " + piAlignmentWidth ); 158 } 159 160 iAlignLen = piAlignmentWidth; 161 oStyleDef = poStyleDef ; 162 163 if ( poPrintWriter == null ) { 164 throw new IllegalArgumentException 165 ( "PrintWriter cannot be null" ); 166 } 167 168 out = poPrintWriter; 169 oAlignmentMarker = poAlignmentMarker; 170 } 171 172 /** 173 * Set the <CODE>PrintWriter</CODE> to output the HTML 174 * to. 175 * 176 * @param poPrintWriter a <code>PrintWriter</code> 177 */ 178 public void setPrintWriter( PrintWriter poPrintWriter ) { 179 180 out = poPrintWriter; 181 182 // initialize other stuff 183 tAlternateSummary = false; 184 iSummaryCount =0; 185 tNeedComma = false; 186 wasEmpty = true; 187 188 align.setLength( 0 ); 189 alignMarkUp1.setLength( 0 ); 190 alignMarkUp2.setLength( 0 ); 191 pcDataBuffer.setLength( 0 ); 192 } 193 194 /** 195 * Returns true if no HitSummary and no Hit elements were 196 * encountered 197 * 198 * @return <code>boolean</code> - true if no summary of Hit elements 199 * where encountered. 200 */ 201 public boolean wasEmpty() { 202 return wasEmpty; 203 } 204 205 /** 206 * Writes out the header section of the report. 207 * 208 * @param oProgram a <code>String</code> - eg 'ncbi-blastp' 209 * @param oVersion a <code>String</code> - eg '2.2.1' 210 * @param oQuery a <code>String</code> - eg 'my query id' 211 * @param oDatabase a <code>String</code>- eg 'embl' 212 */ 213 void writeTitleAndHeader( String oProgram, String oVersion, 214 String oQuery, String oDatabase ) { 215 216 out.print( "<TITLE>" ); 217 out.print( oProgram ); 218 out.print( " version " ); 219 out.print( oVersion ); 220 out.print( " Search Results Query ID : " ); 221 out.print( oQuery ); 222 out.println( "</TITLE>" ); 223 224 out.println( "<table width=\"100%\" border=\"0\" cellpadding=\"3\" cellspacing=\"0\">" ); 225 out.println( " <tr align=\"left\" valign=\"top\">" ); 226 out.println( " <td class=\"titleLevel1\" rowspan=\"3\"><a name=\"#AnchorTop\"></a>Sequence Similarity Report</td>" ); 227 out.println( " <td align=\"right\" class=\"titleLevel1Sub\"> Query Id:</td>" ); 228 out.print( " <td class=\"titleLevel1Sub\">" ); 229 out.print( oQuery ); 230 out.println( " </td>" ); 231 out.println( " </tr><tr align=\"left\" valign=\"top\" class=\"level1titleContainer\"> " ); 232 out.println( " <td class=\"titleLevel1Sub\" align=\"right\">Search Program:</td>" ); 233 out.print( " <td class=\"titleLevel1Sub\">" ); 234 out.print( oProgram ); 235 out.print( " v. " ); 236 out.print( oVersion ); 237 out.println( "</td>" ); 238 out.println( " </tr><tr align=\"left\" valign=\"top\" class=\"level1titleContainer\">" ); 239 out.println( " <td class=\"titleLevel1Sub\" align=\"right\">Database:</td>" ); 240 out.print( " <td class=\"titleLevel1Sub\">" ); 241 out.print( oDatabase ); 242 out.println( "</td>" ); 243 out.println( " </tr>" ); 244 out.println( "</table>" ); 245 } 246 247 248 /** 249 * Returns the appropriate style and javascript definitions for this 250 * renderer. 251 * 252 * @return a <code>String</code> value 253 */ 254 public String getHeaderDefinitions() { 255 256 StringBuffer sb = new StringBuffer(); 257 258 sb.append("<STYLE TYPE=\"text/css\">\n"); 259 sb.append("<!--\n"); 260 sb.append( oStyleDef ); 261 if ( oAlignmentMarker != null ) { 262 sb.append( oAlignmentMarker.getAlignmentStyles() ); 263 } 264 sb.append( "-->\n</STYLE>\n" ); 265 sb.append( oJavaScriptDef ); 266 return sb.substring(0); 267 } 268 269 270 /** 271 * Called when first summary item is reached. 272 * 273 * @param oHitSummary a <code>HitSummary</code> - the first Summary item. 274 */ 275 void startSummaryTable( HitSummary oHitSummary ) { 276 277 wasEmpty = false; 278 279 out.println( "<br>" ); 280 out.println( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" ); 281 out.println( "<tr valign=\"middle\"> " ); 282 out.println( "<td colspan=\"4\" class=\"titleLevel2\" align=\"left\">Overview of Results</td>" ); 283 out.println( "</tr>" ); 284 out.println( "</table>" ); 285 286 out.println( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" ); 287 288 out.println( "<td class=\"titleLevel3\" >" ); 289 out.println( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" ); 290 out.println( "<tr> " ); 291 292 out.println( "<td class=\"titleLevel3\" width=\"40%\" align=\"left\" >Hit Id</td>" ); 293 out.println( "<td class=\"titleLevel3\" width=\"60%\" align=\"left\">Hit Description</td>" ); 294 out.println( "</tr>" ); 295 296 out.println( "</table>" ); 297 out.println( "</td> " ); 298 299 if ( oHitSummary.readingFrame != null ) { 300 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"center\">Frame</td>" ); 301 } 302 303 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"center\">Score</td>" ); 304 305 if ( oHitSummary.expectValue != null ) { 306 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"center\">E value</td>" ); 307 } 308 if ( oHitSummary.smallestSumProbability != null ) { 309 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"center\">P(N)</td>" ); 310 } 311 if ( oHitSummary.numberOfHSPs != null ) { 312 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"left\">HSPs</td>" ); 313 } 314 if ( oHitSummary.numberOfContributingHSPs != null ) { 315 out.println( "<td width=\"7%\" class=\"titleLevel3\" align=\"center\">HSPs</td>" ); 316 } 317 318 out.println( "</tr>" ); 319 // start a new summary table 320 iSummaryCount = 10; 321 } 322 323 324 /** 325 * Called when a hit summary is reached ( except first ). 326 * 327 * @param oHitSummary a <code>HitSummary</code> value 328 */ 329 void writeCurrentSummary( HitSummary oHitSummary ) { 330 331 if ( iSummaryCount == 10 ) { // lets break up that big table 332 iSummaryCount = 0; 333 334 out.println( "</table>" ); 335 out.println 336 ("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"); 337 } 338 339 out.println( "<tr valign=\"middle\" align=\"left\" > " ); 340 341 out.print( "<td class=\"" ); 342 if ( tAlternateSummary ) { 343 out.print( "summaryBodyLineEven" ); 344 } else { 345 out.print( "summaryBodyLineOdd" ); 346 } 347 out.print( "\">" ); 348 349 out.println 350 ("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"); 351 out.println( "<tr> " ); 352 353 out.print( "<td width=\"40%\" class=\"" ); 354 355 if ( tAlternateSummary ) { 356 out.print( "summaryBodyLineEven" ); 357 } else { 358 out.print( "summaryBodyLineOdd" ); 359 } 360 out.print( "\" >" ); 361 362 if ( oFirstURLGenerator!= null ) { 363 364 out.print( "<a href=\"" ); 365 out.print( oFirstURLGenerator.toURL( oHitSummary.oHitId.id, 366 oOptions )); 367 out.print( "\" onMouseOver=\"setStatus('Retrieve hit from database');return document.retVal\" onMouseOut=\"setStatus(' ');return document.retVal\" class=\"dbRetrieve\">" ); 368 out.print( oHitSummary.oHitId.id ); 369 out.print( "</a></td>" ); 370 } else { 371 out.print( oHitSummary.oHitId.id ); 372 out.println( "</td>" ); 373 } 374 375 out.print( "<td width=\"60%\" class=\"" ); 376 if ( tAlternateSummary ) { 377 out.print( "summaryBodyLineEven" ); 378 } else { 379 out.print( "summaryBodyLineOdd" ); 380 } 381 out.print( "\"><a href=\"#Anchor" ); 382 out.print( oHitSummary.oHitId.id ); 383 out.print( "\" onMouseOver=\"setStatus('Jump to detailed results');return document.retVal\" onMouseOut=\"setStatus(' ');return document.retVal\">" ); 384 385 this.writeContentChars( oHitSummary.oDesc.hitDescription ); 386 387 out.println( "</a></td>" ); 388 out.println( "</tr>" ); 389 390 out.println( "</table>" ); 391 out.println( "</td> " ); 392 393 // reading frame 394 this.writeSummaryColumn( oHitSummary.readingFrame, "center" ); 395 396 // score 397 out.print( "<td width=\"7%\" align=\"center\" class=\"" ); 398 if ( tAlternateSummary ) { 399 out.print( "summaryBodyLineEven" ); 400 } else { 401 out.print( "summaryBodyLineOdd" ); 402 } 403 out.print( "\"><a href=\"#Anchor" ); 404 out.print( oHitSummary.oHitId.id ); 405 out.print( "\" onMouseOver=\"setStatus('Jump to detailed results');return document.retVal\" onMouseOut=\"setStatus(' ');return document.retVal\">" ); 406 out.print( oHitSummary.score ); 407 out.println( "</a></td>" ); 408 409 // Expect Value 410 this.writeSummaryColumn( oHitSummary.expectValue, "center" ); 411 // Smallest sum prob 412 this.writeSummaryColumn( oHitSummary.smallestSumProbability, "center" ); 413 // numberOfHSPs 414 this.writeSummaryColumn( oHitSummary.numberOfHSPs, "center"); 415 // numberOfContributingHSPs 416 this.writeSummaryColumn( oHitSummary.numberOfContributingHSPs, "center" ); 417 out.println( "</tr>" ); 418 419 tAlternateSummary = !tAlternateSummary; 420 iSummaryCount ++; 421 } 422 423 /** 424 * Outputs a summary column item. 425 * 426 */ 427 void writeSummaryColumn( String poValue, String poAlign ) { 428 429 if ( poValue != null ) { 430 431 out.print( "<td width=\"7%\" align=\"" ); 432 out.print( poAlign ); 433 out.print( "\" class=\"" ); 434 if ( tAlternateSummary ) { 435 out.print( "summaryBodyLineEven" ); 436 } else { 437 out.print( "summaryBodyLineOdd" ); 438 } 439 out.print( "\">" ); 440 out.print( poValue ); 441 out.println( "</td>" ); 442 } 443 } 444 445 /** 446 * Called when summary table is complete. 447 * 448 */ 449 void endSummaryTable() { 450 451 out.println( "</table>" ); 452 out.println( "<br>" ); 453 454 } 455 456 457 /** 458 * Start the Detail table. 459 * 460 */ 461 void startDetailTable() { 462 463 wasEmpty = false; 464 465 out.println( "<br>" ); 466 out.println( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" ); 467 out.println( "<tr valign=\"middle\"> " ); 468 out.println( "<td class=\"titleLevel2\" align=\"left\">Detailed Analysis of Results</td>" ); 469 out.println( "</tr>" ); 470 out.println( "</table>" ); 471 } 472 473 /** 474 * Write the current detail. 475 * 476 */ 477 void writeCurrentDetail( DetailHit oDetailHit ) { 478 479 out.println 480 ( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\">" ); 481 out.println( "<tr align=\"left\" valign=\"top\"> " ); 482 out.print( "<td class=\"titleLevel3\"> <a name=\"Anchor" ); 483 out.print( oDetailHit.oHitId.id ); 484 out.print( "\"></a>Hit Id : " ); 485 out.print( oDetailHit.oHitId.id ); 486 out.println( "<br><span class=\"titleLevel3Sub\">" ); 487 this.writeContentChars( oDetailHit.oDesc.hitDescription ); 488 out.println( "</span></td>" ); 489 out.println( "<td class=\"titleLevel3\" align=\"right\" color=\"#000000\" ><a href=\"#AnchorTop\" onMouseOver=\"setStatus('Jump to top of document');return document.retVal\" onMouseOut=\"setStatus(' ');return document.retVal\">Top</a></td>" ); 490 out.println( "</tr>" ); 491 out.println( "<tr align=\"left\" valign=\"top\"> " ); 492 out.println( "<td colspan=\"2\"><span class=\"alignment\">" ); 493 out.print( "<p>Sequence length of hit = " ); 494 out.print( oDetailHit.sequenceLength); 495 out.println( "</span></td>" ); 496 out.println( "<br>" ); 497 498 if ( oURLGeneratorList != null && !oURLGeneratorList.isEmpty() ) { 499 out.println( "<tr align=\"left\" valign=\"top\"> " ); 500 501 out.print( "<td colspan=\"" ); 502 out.print( oURLGeneratorList.size() + "" ); 503 out.println( "\"> " ); 504 505 for ( int i =0 ; i < oURLGeneratorList.size() ; i++ ) { 506 507 DatabaseURLGenerator oURLGenerator = ( DatabaseURLGenerator ) 508 oURLGeneratorList.get( i ); 509 out.print( oURLGenerator.toLink( oDetailHit.oHitId.id, 510 oOptions )); 511 } 512 out.println( "</p></td>" ); 513 out.println( "</tr>" ); 514 } 515 516 out.print( "</table>" ); 517 // out.println( "<br>" ); 518 } 519 520 521 522 /** 523 * Utility for writing out each HSP info item, such as 524 * score ot number of identities. 525 * 526 */ 527 void writeHSPInfo( String poName, String poValue ) { 528 529 if ( poValue != null ) { 530 if ( tNeedComma ) { 531 out.print( ", " ); 532 } 533 out.print( poName ); 534 out.print( " = " ); 535 out.print( poValue ); 536 tNeedComma = true; 537 } 538 539 } 540 541 /** 542 * Writes out the current HSP. 543 * 544 */ 545 void writeCurrentHSP( HSPSummary oHSPSummary, BlastLikeAlignment oAlignment ) { 546 tNeedComma = false; 547 548 out.println 549 ( "<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\">" ); 550 out.println( "<tr align=\"left\" valign=\"top\"> " ); 551 out.println 552 ( "<td class=\"titleLevel4\">High-scoring segment pair (HSP) group</td>" ); 553 out.println( "</tr>" ); 554 out.println( "</table>" ); 555 out.println( "<div align=\"right\"><br>" ); 556 out.println 557 ( "<table width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\">" ); 558 out.println( "<tr align=\"left\" valign=\"top\" class=\"level4title\"> " ); 559 out.println( "<td class=\"titleLevel4\"> " ); 560 out.println( "<p>HSP Information<br>" ); 561 562 this.writeHSPInfo( "Score", oHSPSummary.score ); 563 this.writeHSPInfo( "E", oHSPSummary.expectValue ); 564 this.writeHSPInfo( "P", oHSPSummary.pValue ); 565 566 if ( oHSPSummary.numberOfIdentities != null || 567 oHSPSummary.percentageIdentity != null ) { 568 569 out.print( ", Identities = " ); 570 if ( oHSPSummary.numberOfIdentities != null ) { 571 out.print( oHSPSummary.numberOfIdentities ); 572 573 if ( oHSPSummary.alignmentSize != null ) { 574 out.print( "/" ); 575 out.print( oHSPSummary.alignmentSize ); 576 } 577 578 if ( oHSPSummary.percentageIdentity != null ) { 579 out.print( " (" ); 580 out.print( oHSPSummary.percentageIdentity ); 581 out.print( "%)" ); 582 } 583 } 584 } 585 586 if ( oHSPSummary.numberOfPositives != null || 587 oHSPSummary.percentagePositives != null ) { 588 589 out.print( ", Positives = " ); 590 if ( oHSPSummary.numberOfPositives != null ) { 591 out.print( oHSPSummary.numberOfPositives ); 592 593 if ( oHSPSummary.alignmentSize != null ) { 594 out.print( "/" ); 595 out.print( oHSPSummary.alignmentSize ); 596 } 597 598 if ( oHSPSummary.percentagePositives != null ) { 599 out.print( " (" ); 600 out.print( oHSPSummary.percentagePositives ); 601 out.print( "%)" ); 602 } 603 } 604 } 605 606 this.writeHSPInfo( "Length", oHSPSummary.alignmentSize ); 607 this.writeHSPInfo( "Query Frame", 608 this.toSign( oHSPSummary.queryFrame ) ); 609 this.writeHSPInfo( "Hit Frame", 610 this.toSign( oHSPSummary.hitFrame ) ); 611 612 if ( oHSPSummary.queryFrame == null ) { 613 this.writeHSPInfo( "Query Strand", 614 this.toSign( oHSPSummary.queryStrand ) ); 615 } 616 if ( oHSPSummary.hitFrame == null ) { 617 this.writeHSPInfo( "Hit Strand", 618 this.toSign( oHSPSummary.hitStrand )); 619 } 620 621 this.writeHSPInfo( "P(N)", oHSPSummary.sumPValues ); 622 this.writeHSPInfo( "No. of gaps", oHSPSummary.numberOfGaps ); 623 624 out.println( "</p>" ); 625 out.println( "</td>" ); 626 out.println( "</tr>" ); 627 out.println( "</table>" ); 628 out.println( "</div>" ); 629 630 out.println( "<div align=\"right\">" ); 631 out.println( "<table width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"5\">" ); 632 out.println( "<tr> " ); 633 out.println( "<td> </td>" ); 634 out.println( "</tr>" ); 635 636 this.drawCurrentAlignment( oAlignment ); 637 638 out.println( "</table>" ); 639 out.println( "</div>" ); 640 } 641 642 /** 643 * Draws one block of the alignment. 644 */ 645 String drawSubAlignment( String piQueryStart, 646 String piQueryStop, 647 String piHitStart, 648 String piHitStop, 649 String poQuery, 650 String poConsensus, 651 String poHit ) { 652 653 align.setLength( 0 ); 654 655 int iMax = 4; 656 657 if ( piQueryStart.length() > iMax ) { 658 iMax = piQueryStart.length(); 659 } 660 if ( piHitStart.length() > iMax ) { 661 iMax = piHitStart.length(); 662 } 663 iMax = iMax+2; 664 665 String[] oFormattedSeq = new String[]{ poQuery, poHit, poConsensus }; 666 if ( oAlignmentMarker != null ) { 667 oAlignmentMarker.alignment2HTML( oFormattedSeq ); 668 } 669 670 String oConsensusPad = " "; 671 oConsensusPad = oConsensusPad.concat( this.padTo( "", iMax) ); 672 673 align.append( "<tr align=\"left\" valign=\"top\"> " ); 674 align.append( "\n"); 675 align.append( "<td>" ); 676 align.append( "\n"); 677 align.append( "<pre><span class=\"alignment\">Query: " ); 678 align.append( this.padTo( piQueryStart, iMax) ); 679 680 align.append( oFormattedSeq[0] ); 681 align.append( " "); 682 align.append( this.padTo( piQueryStop, iMax) ); 683 684 align.append( "\n"); 685 686 align.append( oConsensusPad ); 687 688 align.append( oFormattedSeq[2] ); 689 align.append( "\n"); 690 align.append( "Hit : " ); 691 align.append( this.padTo( piHitStart, iMax ) ); 692 693 align.append( oFormattedSeq[1] ); 694 align.append( " "); 695 align.append( this.padTo( piHitStop, iMax) ); 696 align.append( "</span></PRE> " ); 697 align.append( "\n"); 698 align.append( "" ); 699 align.append( "\n"); 700 align.append( "</td>" ); 701 align.append( "\n"); 702 align.append( "</tr>" ); 703 align.append( "\n"); 704 705 return align.substring(0); 706 } 707 708 709 /** 710 * Draws a full alignment block. 711 */ 712 void drawCurrentAlignment( BlastLikeAlignment oAlignment ) { 713 714 int i = 0; 715 716 int iCurrentQueryStart = Integer.parseInt 717 ( oAlignment.oQuerySeq.startPosition ); 718 int iCurrentHitStart = Integer.parseInt 719 ( oAlignment.oHitSeq.startPosition ); 720 721 int iQueryLen = oAlignment.oQuerySeq.seq.length(); 722 int iHitLen = oAlignment.oHitSeq.seq.length(); 723 724 int iNumberOfQueryGaps = 0; 725 int iNumberOfHitGaps = 0; 726 int index = -1; 727 while ( ( index = oAlignment.oQuerySeq.seq.indexOf( '-', index+1 ) ) != -1 ) { 728 iNumberOfQueryGaps++; 729 } 730 index = -1; 731 while ( ( index = oAlignment.oHitSeq.seq.indexOf( '-', index+1 ) ) != -1 ) { 732 iNumberOfHitGaps++; 733 } 734 735 int iQStop = Integer.parseInt( oAlignment.oQuerySeq.stopPosition ); 736 int iHStop = Integer.parseInt( oAlignment.oHitSeq.stopPosition ); 737 738 739 int queryDirection = 1; 740 int hitDirection = 1; 741 742 if ( iQStop < iCurrentQueryStart ) { 743 queryDirection = -1; 744 } 745 if ( iHStop < iCurrentHitStart ) { 746 hitDirection = -1; 747 } 748 749 int iQueryMultiplier = (( iQStop - iCurrentQueryStart ) + queryDirection)/ 750 ( iQueryLen - iNumberOfQueryGaps ); 751 752 int iHitMultiplier = (( iHStop - iCurrentHitStart ) + hitDirection )/ 753 ( iHitLen - iNumberOfHitGaps ); 754 755 int iCurrentQueryEnd = 0; 756 int iCurrentHitEnd = 0; 757 758 759 // 760 // 761 // Substring ( i*iAlignLen, (i+1)*iAlignLen ) 762 // 763 // Increment the end number by ( (iAlign-numberofgaps)* multiplier ) 764 // 765 // The end check should be the current end number 766 // 767 768 while( ((i+1)*iAlignLen) < iQueryLen ) { 769 770 String oCurrentQueryString = oAlignment.oQuerySeq.seq.substring 771 ( i*iAlignLen, (i+1)*iAlignLen ); 772 String oCurrentHitString = oAlignment.oHitSeq.seq.substring 773 ( i*iAlignLen, (i+1)*iAlignLen ); 774 775 iNumberOfQueryGaps = this.countNumberOfGaps( oCurrentQueryString ); 776 iNumberOfHitGaps = this.countNumberOfGaps( oCurrentHitString ); 777 778 iCurrentQueryEnd = iCurrentQueryStart + 779 ( ( iAlignLen - iNumberOfQueryGaps ) * iQueryMultiplier ); 780 iCurrentHitEnd = iCurrentHitStart + 781 (( iAlignLen - iNumberOfHitGaps ) * iHitMultiplier ); 782 783 out.println( drawSubAlignment 784 ( iCurrentQueryStart + "", 785 (iCurrentQueryEnd - queryDirection) + "", 786 iCurrentHitStart + "", 787 (iCurrentHitEnd - hitDirection) + "", 788 oCurrentQueryString, 789 oAlignment.oConsensus.substring 790 ( i*iAlignLen, (i+1)*iAlignLen ) , 791 oCurrentHitString ) 792 ); 793 i++; 794 iCurrentQueryStart += ( ( iAlignLen - iNumberOfQueryGaps ) 795 * iQueryMultiplier ); 796 iCurrentHitStart += ( ( iAlignLen - iNumberOfHitGaps ) 797 * iHitMultiplier ); 798 799 } // end while 800 801 if ( iQStop != iCurrentQueryEnd ) { 802 803 iCurrentQueryEnd = iQStop; 804 iCurrentHitEnd = iHStop; 805 806 out.println( drawSubAlignment( iCurrentQueryStart + "", 807 iCurrentQueryEnd + "", 808 iCurrentHitStart + "", 809 iCurrentHitEnd + "", 810 oAlignment.oQuerySeq.seq.substring 811 ( i*iAlignLen ) , 812 oAlignment.oConsensus.substring 813 ( i*iAlignLen ) , 814 oAlignment.oHitSeq.seq.substring 815 ( i*iAlignLen ) ) 816 ); 817 } 818 819 } 820 821 /** 822 * Renderers end of detail table 823 * 824 */ 825 void endDetailTable() { 826 out.println 827 ( "<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">" ); 828 out.println( "<tr> " ); 829 out.println( "<td class=\"footer\" height=\"21\"> " ); 830 out.println 831 ("<div align=\"center\"> <a href=\"http://www.biojava.org/\" class=\"footer\"> </a> " ); 832 out.println 833 ( "Produced using <a href=\"http://www.biojava.org/\" class=\"footer\">biojava</a> " ); 834 out.println( "- www.biojava.org</div>" ); 835 out.println( "</td>" ); 836 out.println( "</tr>" ); 837 out.println( "</table>" ); 838 } 839 840 841 /** 842 * Convert from 'plus' and 'minus' to '+' and '-' 843 * 844 * @param poString <code>String</code> to convert. 845 * @return new <code>String</code> 846 */ 847 private String toSign( String poString ) { 848 849 String oSign = null; 850 851 if ( poString != null ) { 852 if ( poString.startsWith( "plus" ) ) { 853 oSign = "+"; 854 if ( poString.length() > 4 ) { 855 oSign = oSign.concat( poString.substring( 4 )); 856 } 857 858 } else if ( poString.startsWith( "minus" )) { 859 oSign = "-"; 860 if ( poString.length() > 5 ) { 861 oSign = oSign.concat( poString.substring( 5 )); 862 } 863 } 864 } 865 return oSign; 866 } 867 868 // ************************************************************ // 869 // * Escape HTML chars * // 870 // * * // 871 // * Probably replace this with something in a apache or * // 872 // * java lib. * // 873 // * * // 874 // * * // 875 // ************************************************************ // 876 877 private void writeContentChars( String poLine ) { 878 879 poLine = this.replace( poLine, '&', "&"); 880 poLine = this.replaceGtLtAndQuote( poLine ); 881 882 out.print( poLine ); 883 } 884 885 private String replaceGtLtAndQuote( String poInputString ) { 886 887 pcDataBuffer.setLength( 0 ); 888 pcDataBuffer.append( poInputString ); 889 int iLength = ( pcDataBuffer.length() ); 890 891 for (int i = iLength; --i >= 0; ) { 892 if ( (pcDataBuffer.charAt(i) == '<') ) { 893 pcDataBuffer.deleteCharAt(i); 894 // then insert escape char to the LHS 895 pcDataBuffer.insert(i, "<" ); 896 } else if ( (pcDataBuffer.charAt(i) == '>') ) { 897 pcDataBuffer.deleteCharAt(i); 898 // then insert escape char to the LHS 899 pcDataBuffer.insert(i, ">" ); 900 } else if ( (pcDataBuffer.charAt(i) == '\\') ) { 901 pcDataBuffer.deleteCharAt(i); 902 // then insert escape char to the LHS 903 pcDataBuffer.insert(i, """ ); 904 } // end if 905 } // end for 906 907 return pcDataBuffer.substring(0); 908 } 909 910 private String replace( String poInputString, 911 char pcCharToReplace, 912 String poReplacementString ) { 913 914 pcDataBuffer.setLength( 0 ); 915 pcDataBuffer.append( poInputString ); 916 int iLength = ( pcDataBuffer.length() ); 917 918 for (int i = iLength; --i >= 0; ) { 919 if ( pcDataBuffer.charAt(i) == pcCharToReplace ) { 920 pcDataBuffer.deleteCharAt(i); 921 // then insert escape char to the LHS 922 pcDataBuffer.insert(i, poReplacementString ); 923 } // end if 924 } // end for 925 926 return pcDataBuffer.substring(0); 927 } 928 929 930 /** 931 * Makes assumption about the gap character. 932 * 933 */ 934 int countNumberOfGaps( String poString ) { 935 936 int index = -1; 937 int iNumberOfGaps = 0; 938 while ( ( index = poString.indexOf( '-', index+1 ) ) != -1 ) { 939 iNumberOfGaps++; 940 } 941 return iNumberOfGaps; 942 } 943 944 /** 945 * Ensures the given string is the correct length. 946 * 947 */ 948 String padTo( String poString, int iNumberOfChars ) { 949 950 int iLen = iNumberOfChars - poString.length(); 951 952 if ( iLen > padding.length ) { 953 padding = new char[ iLen ]; 954 Arrays.fill( padding, 955 0, 956 iLen, 957 ' ' ); 958 } 959 return poString.concat( String.copyValueOf( padding, 0, iLen ) ); 960 } 961 962 963} // end class 964