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.gui.sequence; 023 024import java.awt.Color; 025import java.awt.Font; 026import java.awt.Graphics2D; 027import java.awt.Paint; 028import java.awt.event.MouseEvent; 029import java.awt.geom.AffineTransform; 030import java.awt.geom.Rectangle2D; 031import java.util.List; 032 033import org.biojava.bio.BioRuntimeException; 034import org.biojava.bio.seq.io.SymbolTokenization; 035import org.biojava.bio.symbol.Location; 036import org.biojava.bio.symbol.SymbolList; 037 038/** 039 * <code>SymbolSequenceRenderer</code> renders symbols of a 040 * <code>SymbolList</code>. 041 * 042 * @author Matthew Pocock 043 * @author Thomas Down 044 * @author David Huen 045 * @author Keith James 046 * @author Kalle Näslund 047 */ 048public class SymbolSequenceRenderer implements SequenceRenderer 049{ 050 private double depth = 25.0; 051 private Paint outline; 052 053 public SymbolSequenceRenderer() 054 { 055 outline = Color.black; 056 } 057 058 public double getDepth(SequenceRenderContext context) 059 { 060 return depth + 1.0; 061 } 062 063 public double getMinimumLeader(SequenceRenderContext context) 064 { 065 return 0.0; 066 } 067 068 public double getMinimumTrailer(SequenceRenderContext context) 069 { 070 return 0.0; 071 } 072 073 public void paint(Graphics2D g2, SequenceRenderContext context) 074 { 075 Rectangle2D prevClip = g2.getClipBounds(); 076 AffineTransform prevTransform = g2.getTransform(); 077 078 g2.setPaint(outline); 079 080 Font font = context.getFont(); 081 082 Rectangle2D maxCharBounds = 083 font.getMaxCharBounds(g2.getFontRenderContext()); 084 085 double scale = context.getScale(); 086 087 if (scale >= (maxCharBounds.getWidth() * 0.3) && 088 scale >= (maxCharBounds.getHeight() * 0.3)) 089 { 090 double xFontOffset = 0.0; 091 double yFontOffset = 0.0; 092 093 // These offsets are not set quite correctly yet. The 094 // Rectangle2D from getMaxCharBounds() seems slightly 095 // off. The "correct" application of translations based on 096 // the Rectangle2D seem to give the wrong results. The 097 // values below are mostly fudges. 098 if (context.getDirection() == SequenceRenderContext.HORIZONTAL) 099 { 100 xFontOffset = maxCharBounds.getCenterX() * 0.25; 101 yFontOffset = - maxCharBounds.getCenterY() + (depth * 0.5); 102 } 103 else 104 { 105 xFontOffset = - maxCharBounds.getCenterX() + (depth * 0.5); 106 yFontOffset = - maxCharBounds.getCenterY() * 3.0; 107 } 108 109 SymbolList seq = context.getSymbols(); 110 SymbolTokenization toke = null; 111 try { 112 toke = seq.getAlphabet().getTokenization("token"); 113 } catch (Exception ex) { 114 throw new BioRuntimeException(ex); 115 } 116 117 Location visible = GUITools.getVisibleRange(context, g2); 118 for (int sPos = visible.getMin(); sPos <= visible.getMax(); sPos++) 119 { 120 double gPos = context.sequenceToGraphics(sPos); 121 String s = "?"; 122 try { 123 s = toke.tokenizeSymbol(seq.symbolAt(sPos)); 124 } catch (Exception ex) { 125 // We'll ignore the case of not being able to tokenize it 126 } 127 128 if (context.getDirection() == SequenceRenderContext.HORIZONTAL) 129 { 130 g2.drawString(s, 131 (float) (gPos + xFontOffset), 132 (float) yFontOffset); 133 } 134 else 135 { 136 g2.drawString(s, 137 (float) xFontOffset, 138 (float) (gPos + yFontOffset)); 139 } 140 } 141 } 142 143 g2.setClip(prevClip); 144 g2.setTransform(prevTransform); 145 } 146 147 public SequenceViewerEvent processMouseEvent(SequenceRenderContext context, 148 MouseEvent me, 149 List path) 150 { 151 path.add(this); 152 int sPos = context.graphicsToSequence(me.getPoint()); 153 return new SequenceViewerEvent(this, null, sPos, me, path); 154 } 155}