001/* 002 * BioJava development code This code may be freely distributed and modified 003 * under the terms of the GNU Lesser General Public Licence. This should be 004 * distributed with the code. If you do not have a copy, see: 005 * http://www.gnu.org/copyleft/lesser.html Copyright for this code is held 006 * jointly by the individual authors. These should be listed in @author doc 007 * comments. For more information on the BioJava project and its aims, or to 008 * join the biojava-l mailing list, visit the home page at: 009 * http://www.biojava.org/ 010 */ 011package org.biojava.bio.gui.sequence; 012 013import java.awt.Graphics2D; 014import java.awt.event.MouseEvent; 015import java.awt.geom.Rectangle2D; 016import java.util.ArrayList; 017import java.util.List; 018import java.util.NoSuchElementException; 019 020import org.biojava.bio.gui.glyph.ArrowGlyph; 021import org.biojava.bio.gui.glyph.Glyph; 022import org.biojava.bio.seq.Feature; 023import org.biojava.bio.seq.FeatureFilter; 024import org.biojava.bio.seq.FeatureHolder; 025import org.biojava.bio.seq.StrandedFeature; 026import org.biojava.utils.ChangeVetoException; 027 028/** 029 * A FeatureRenderer that renders a particular Glyph for Features accepted by a 030 * particular FeatureFilter 031 * 032 * @author Mark Southern 033 * @author <a href="mailto:andreas.draeger@uni-tuebingen.de">Andreas Dräger</a> 034 * @see org.biojava.bio.gui.glyph.Glyph 035 * @since 1.5 036 */ 037public class GlyphFeatureRenderer extends FilteringRenderer implements 038 FeatureRenderer { 039 /** 040 * 041 */ 042 private static final long serialVersionUID = 7005846487574725181L; 043 044 private double depth = 15; 045 046 protected List<FeatureFilter> fList; 047 048 protected List<Glyph> gList; 049 050 public GlyphFeatureRenderer() { 051 super(); 052 fList = new ArrayList<FeatureFilter>(); 053 gList = new ArrayList<Glyph>(); 054 } 055 056 public void addFilterAndGlyph(FeatureFilter ff, Glyph g) 057 throws ChangeVetoException { 058 if (!fList.contains(ff)) { 059 fList.add(ff); 060 gList.add(g); 061 062 if (fList.size() == 0) 063 setFilter(FeatureFilter.none); 064 else { 065 FeatureFilter f = fList.get(0); 066 if (fList.size() > 1) for (int i = 1; i < fList.size(); i++) 067 f = new FeatureFilter.Or(f, fList.get(i)); 068 setFilter(f); 069 } 070 } 071 } 072 073 public void removeFilterWithGlyph(FeatureFilter ff) 074 throws ChangeVetoException { 075 if (fList.contains(ff)) { 076 gList.remove(fList.indexOf(ff)); 077 fList.remove(ff); 078 if (fList.size() == 0) { 079 setFilter(FeatureFilter.none); 080 } else { 081 FeatureFilter f = fList.get(0); 082 if (fList.size() > 1) for (int i = 1; i < fList.size(); i++) 083 f = new FeatureFilter.Or(f, fList.get(i)); 084 setFilter(f); 085 } 086 } 087 } 088 089 /** 090 * Returns the ith {@link FeatureFilter} in this renderer. 091 * 092 * @param i 093 * @return the featureFilter 094 */ 095 public FeatureFilter getFeatureFilter(int i) { 096 return fList.get(i); 097 } 098 099 /** 100 * Returns true if the given {@link FeatureFilter} is already contained in this 101 * renderer. 102 * 103 * @param ff 104 * @return flag if featurefilter is contained 105 */ 106 public boolean containsFilter(FeatureFilter ff) { 107 return fList.contains(ff); 108 } 109 110 /** 111 * Allows setting another {@link Glyph } object to be painted for the given 112 * FeatureFilter. 113 * 114 * @param ff 115 * @param glyph 116 * @throws ChangeVetoException 117 */ 118 public void setGlyphForFilter(FeatureFilter ff, Glyph glyph) 119 throws NoSuchElementException { 120 if (fList.contains(ff)) 121 gList.set(fList.indexOf(ff), glyph); 122 else throw new NoSuchElementException(ff.toString()); 123 } 124 125 /** 126 * Returns the {@link Glyph} object which is assigned to the given feature 127 * filter. 128 * 129 * @param ff 130 * @return {@link Glyph} object 131 * @throws NoSuchElementException 132 */ 133 public Glyph getGlyphForFilter(FeatureFilter ff) 134 throws NoSuchElementException { 135 if (fList.contains(ff)) return gList.get(fList.indexOf(ff)); 136 throw new NoSuchElementException(ff.toString()); 137 } 138 139 public void setDepth(double depth) { 140 this.depth = depth; 141 } 142 143 /** 144 * Returns the depth property of this class. 145 * 146 * @return the depth 147 */ 148 public double getDepth(SequenceRenderContext src) { 149 return depth; 150 } 151 152 public FeatureHolder processMouseEvent(FeatureHolder fh, 153 SequenceRenderContext src, MouseEvent me) { 154 return fh; 155 } 156 157 public void renderFeature(Graphics2D g2, Feature f, SequenceRenderContext src) { 158 float minBounds = (float) src.sequenceToGraphics(f.getLocation().getMin()); 159 float maxBounds = (float) src 160 .sequenceToGraphics(f.getLocation().getMax() + 1); 161 Rectangle2D.Float bounds; 162 bounds = new Rectangle2D.Float(minBounds, 0, maxBounds - minBounds, 163 (float) depth); 164 165 for (int i = 0; i < fList.size(); i++) 166 if (fList.get(i).accept(f)) { 167 Glyph g = gList.get(i); 168 g.setBounds(bounds); 169 if ((g instanceof ArrowGlyph) && (f instanceof StrandedFeature)) 170 ((ArrowGlyph) g).setDirection(((StrandedFeature) f).getStrand() 171 .getValue()); 172 if (src.getDirection() == SequenceRenderContext.HORIZONTAL) 173 g.render(g2); 174 } 175 } 176}