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.Graphics2D; 026import java.awt.Paint; 027import java.awt.Shape; 028import java.awt.event.MouseEvent; 029import java.awt.geom.GeneralPath; 030 031import org.biojava.bio.seq.Feature; 032import org.biojava.bio.seq.FeatureHolder; 033import org.biojava.bio.seq.StrandedFeature; 034import org.biojava.bio.symbol.Location; 035import org.biojava.utils.AbstractChangeable; 036import org.biojava.utils.ChangeEvent; 037import org.biojava.utils.ChangeSupport; 038import org.biojava.utils.ChangeType; 039import org.biojava.utils.ChangeVetoException; 040 041/** 042 * @author Thomas Down 043 * @author Matthew Pocock 044 * @author David Huen 045 */ 046public class TickFeatureRenderer 047extends AbstractChangeable 048implements FeatureRenderer { 049 public static final ChangeType FILL = new ChangeType( 050 "The fill paint has changed", 051 "org.biojava.bio.gui.sequence.TickFeatureRenderer", 052 "FILL" 053 ); 054 055 public static final ChangeType OUTLINE = new ChangeType( 056 "The outline paint has changed", 057 "org.biojava.bio.gui.sequence.TickFeatureRenderer", 058 "OUTLINE" 059 ); 060 061 public static final ChangeType DEPTH = new ChangeType( 062 "The size of the arrow has changed", 063 "org.biojava.bio.gui.sequence.TickFeatureRenderer", 064 "DEPTH" 065 ); 066 067 private Paint fill; 068 private Paint outline; 069 private double depth = 25.0; 070 071 public TickFeatureRenderer() { 072 fill = Color.blue; 073 outline = Color.black; 074 } 075 076 public void setFill(Paint p) 077 throws ChangeVetoException { 078 if(hasListeners()) { 079 ChangeSupport cs = getChangeSupport(SequenceRenderContext.REPAINT); 080 synchronized(cs) { 081 ChangeEvent ce = new ChangeEvent( 082 this, SequenceRenderContext.REPAINT, 083 null, null, new ChangeEvent( 084 this, FILL, p, fill 085 ) 086 ); 087 cs.firePreChangeEvent(ce); 088 fill = p; 089 cs.firePostChangeEvent(ce); 090 } 091 } else { 092 fill = p; 093 } 094 } 095 096 public Paint getFill() { 097 return fill; 098 } 099 100 public void setOutline(Paint p) 101 throws ChangeVetoException { 102 if(hasListeners()) { 103 ChangeSupport cs = getChangeSupport(SequenceRenderContext.REPAINT); 104 synchronized(cs) { 105 ChangeEvent ce = new ChangeEvent( 106 this, SequenceRenderContext.REPAINT, 107 null, null, new ChangeEvent( 108 this, OUTLINE, p, outline 109 ) 110 ); 111 cs.firePreChangeEvent(ce); 112 outline = p; 113 cs.firePostChangeEvent(ce); 114 } 115 } else { 116 outline = p; 117 } 118 } 119 120 public Paint getOutline() { 121 return outline; 122 } 123 124 public void setDepth(double arrowSize) 125 throws ChangeVetoException { 126 if(hasListeners()) { 127 ChangeSupport cs = getChangeSupport(SequenceRenderContext.LAYOUT); 128 synchronized(cs) { 129 ChangeEvent ce = new ChangeEvent( 130 this, SequenceRenderContext.LAYOUT, 131 null, null, new ChangeEvent( 132 this, DEPTH, new Double(this.depth), new Double(arrowSize) 133 ) 134 ); 135 cs.firePreChangeEvent(ce); 136 this.depth = arrowSize; 137 cs.firePostChangeEvent(ce); 138 } 139 } else { 140 this.depth = arrowSize; 141 } 142 } 143 144 public double getDepth() { 145 return depth; 146 } 147 148 public void renderFeature( 149 Graphics2D g, 150 Feature f, 151 SequenceRenderContext src 152 ) { 153 Shape s = null; 154 Location loc = f.getLocation(); 155 float min = (float) src.sequenceToGraphics(loc.getMin()); 156 float max = (float) src.sequenceToGraphics(loc.getMax()); 157 float pos = (min + max) / 2; 158 159 float fDepth = (float) depth; 160 float fDepthByThree = fDepth / 3.0F; 161 162 if (f instanceof StrandedFeature) { 163 StrandedFeature.Strand strand = ((StrandedFeature) f).getStrand(); 164 if(src.getDirection() == SequenceRenderContext.HORIZONTAL) { 165 if(strand == StrandedFeature.POSITIVE) { 166 GeneralPath path = new GeneralPath(); 167 path.moveTo(pos, 0.0F); 168 path.lineTo(pos, fDepth); 169 path.lineTo(pos + fDepthByThree, fDepth); 170 path.lineTo(pos, fDepth - fDepthByThree); 171 path.closePath(); 172 s = path; 173 } else if(strand == StrandedFeature.NEGATIVE) { 174 GeneralPath path = new GeneralPath(); 175 path.moveTo(pos, 0.0F); 176 path.lineTo(pos, fDepth); 177 path.lineTo(pos - fDepthByThree, fDepth); 178 path.lineTo(pos, fDepth - fDepthByThree); 179 path.closePath(); 180 s = path; 181 } 182 } else { // vertical 183 if(strand == StrandedFeature.POSITIVE) { 184 GeneralPath path = new GeneralPath(); 185 path.moveTo(0.0F, pos); 186 path.lineTo(fDepth, pos); 187 path.lineTo(fDepth, pos + fDepthByThree); 188 path.lineTo(fDepth - fDepthByThree, pos); 189 path.closePath(); 190 s = path; 191 } else if(strand == StrandedFeature.NEGATIVE) { 192 GeneralPath path = new GeneralPath(); 193 path.moveTo(0.0F, pos); 194 path.lineTo(fDepth, pos); 195 path.lineTo(fDepth, pos - fDepthByThree); 196 path.lineTo(fDepth - fDepthByThree, pos); 197 path.closePath(); 198 s = path; 199 } 200 } 201 } 202 203 if(fill != null) { 204 Paint prevPaint = g.getPaint(); 205 g.setPaint(fill); 206 g.fill(s); 207 g.setPaint(prevPaint); 208 } 209 if (outline != null) { 210 Paint prevPaint = g.getPaint(); 211 g.setPaint(outline); 212 g.draw(s); 213 g.setPaint(prevPaint); 214 } 215 } 216 217 public double getDepth(SequenceRenderContext src) { 218 return depth; 219 } 220 221 public FeatureHolder processMouseEvent( 222 FeatureHolder hits, 223 SequenceRenderContext src, 224 MouseEvent me 225 ) { 226 return hits; 227 } 228}