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.Graphics2D;
025import java.awt.event.MouseEvent;
026import java.io.Serializable;
027import java.util.List;
028
029import org.biojava.utils.AbstractChangeable;
030import org.biojava.utils.ChangeEvent;
031import org.biojava.utils.ChangeForwarder;
032import org.biojava.utils.ChangeSupport;
033import org.biojava.utils.ChangeType;
034import org.biojava.utils.ChangeVetoException;
035import org.biojava.utils.Changeable;
036
037/**
038 * An implementation of SequenceRenderer that delegates rendering to another
039 * renderer.
040 * 
041 * <p>
042 * This takes care of all event notification and method invocation for you.
043 * Subclass this and over-ride methods, and then possibly call the method on
044 * super to forward the call on to the wrapped renderer.
045 * </p>
046 *
047 * @author Matthew Pocock
048 */
049public class SequenceRendererWrapper
050extends AbstractChangeable
051implements SequenceRenderer, Serializable {
052  public static ChangeType RENDERER = new ChangeType(
053    "The renderer used to render the filtered features has changed",
054    "org.biojava.bio.gui.sequence.FilteringRenderer",
055    "RENDERER",
056    SequenceRenderContext.LAYOUT
057  );
058  
059  private SequenceRenderer renderer;
060  private transient ChangeForwarder rendForwarder;
061
062  /**
063   *  Create a new renderer with no wrapped renderer.
064   *
065   * It is important that you call setRenderer() on this instance before
066   * trying to use it to display anything.
067   */
068  public SequenceRendererWrapper() {}
069
070  /**
071   * Create a new wrapper with a wrapped renderer
072   *
073   * @param renderer  the SequenceRenderer to wrap up
074   */
075  public SequenceRendererWrapper(SequenceRenderer renderer) {
076    this.renderer = renderer;
077  }
078  
079  protected ChangeSupport getChangeSupport(ChangeType ct) {
080    ChangeSupport cs = super.getChangeSupport(ct);
081    
082    if(rendForwarder == null) {
083      rendForwarder = new SequenceRenderer.RendererForwarder(this, cs);
084      if((renderer != null) && (renderer instanceof Changeable)) {
085        Changeable c = (Changeable) this.renderer;
086        c.addChangeListener(
087          rendForwarder,
088          SequenceRenderContext.REPAINT
089        );
090      }
091    }
092    
093    return cs;
094  }
095  
096  public void setRenderer(SequenceRenderer renderer)
097  throws ChangeVetoException {
098    if(hasListeners()) {
099      ChangeEvent ce = new ChangeEvent(
100        this, RENDERER,
101        renderer, this.renderer
102      );
103      ChangeSupport cs = getChangeSupport(RENDERER);
104      synchronized(cs) {
105        cs.firePreChangeEvent(ce);
106        if((this.renderer != null) && (this.renderer instanceof Changeable)) {
107          Changeable c = (Changeable) this.renderer;
108          c.removeChangeListener(rendForwarder);
109        }
110        this.renderer = renderer;
111        if(renderer instanceof Changeable) {
112          Changeable c = (Changeable) renderer;
113          c.addChangeListener(rendForwarder);
114        }
115        cs.firePostChangeEvent(ce);
116      }
117    } else {
118      this.renderer = renderer;
119    }
120  }
121  
122  public SequenceRenderer getRenderer() {
123    return this.renderer;
124  }
125  
126  public double getDepth(SequenceRenderContext src) {
127    SequenceRenderer sr = getRenderer();
128    if(sr == null) {
129      return 0.0;
130    } else {
131      return sr.getDepth(src);
132    }
133  }
134  
135  public double getMinimumLeader(SequenceRenderContext src) {
136    SequenceRenderer sr = getRenderer();
137    if(sr == null) {
138      return 0.0;
139    } else {
140      return sr.getMinimumLeader(src);
141    }
142  }
143  
144  public double getMinimumTrailer(SequenceRenderContext src) {
145    SequenceRenderer sr = getRenderer();
146    if(sr == null) {
147      return 0.0;
148    } else {
149      return sr.getMinimumTrailer(src);
150    }
151  }
152  
153  public void paint(
154    Graphics2D g,
155    SequenceRenderContext src
156  ) {
157    SequenceRenderer sr = getRenderer();
158    if(sr != null) {
159      sr.paint(g, src);
160    }
161  }
162  
163  public SequenceViewerEvent processMouseEvent(
164    SequenceRenderContext src,
165    MouseEvent me,
166    List path
167  ) {
168    path.add(this);
169    return getRenderer().processMouseEvent(src, me, path);
170  }
171}
172