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.ArrayList; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.List; 031 032import org.biojava.utils.AbstractChangeable; 033import org.biojava.utils.ChangeEvent; 034import org.biojava.utils.ChangeForwarder; 035import org.biojava.utils.ChangeSupport; 036import org.biojava.utils.ChangeType; 037import org.biojava.utils.ChangeVetoException; 038import org.biojava.utils.Changeable; 039 040/** 041 * <code>MultiLineRenderer</code> is a <code>SequenceRenderer</code> 042 * which collects a number of other <code>SequenceRenderer</code>s 043 * each of which render their own view of a <code>Sequence</code>. 044 * 045 * @author Matthew Pocock 046 * @author Keith James 047 */ 048public class MultiLineRenderer extends AbstractChangeable 049 implements SequenceRenderer, Serializable { 050 public static final ChangeType RENDERERS = 051 new ChangeType("A SequenceRenderer has been added or removed.", 052 "org.biojava.bio.gui.sequence.MultiLineRenderer", 053 "RENDERERS", 054 SequenceRenderContext.LAYOUT); 055 056 protected List renderers = new ArrayList(); 057 private transient ChangeForwarder rendererForwarder = null; 058 059 protected ChangeSupport getChangeSupport(ChangeType ct) { 060 ChangeSupport cs = super.getChangeSupport(ct); 061 062 if (rendererForwarder == null) { 063 rendererForwarder = new SequenceRenderer.RendererForwarder(this, cs); 064 for (Iterator i = renderers.iterator(); i.hasNext(); ) { 065 SequenceRenderer sRend = (SequenceRenderer) i.next(); 066 if (sRend instanceof Changeable) { 067 Changeable c = (Changeable) sRend; 068 c.addChangeListener(rendererForwarder, 069 SequenceRenderContext.REPAINT); 070 } 071 } 072 } 073 074 return cs; 075 } 076 077 /** 078 * <code>addRenderer</code> adds a renderer as a new track. 079 * 080 * @param renderer a <code>SequenceRenderer</code> to add. 081 * 082 * @exception ChangeVetoException if the renderer cannot be added. 083 */ 084 public void addRenderer(SequenceRenderer renderer) 085 throws ChangeVetoException { 086 if (hasListeners()) { 087 ChangeEvent ce = new ChangeEvent(this, RENDERERS, renderer, null); 088 ChangeSupport cs = getChangeSupport(RENDERERS); 089 090 synchronized(cs) { 091 cs.firePreChangeEvent(ce); 092 _addRenderer(renderer); 093 if (renderer instanceof Changeable) { 094 Changeable c = (Changeable) renderer; 095 c.addChangeListener(rendererForwarder, 096 SequenceRenderContext.REPAINT); 097 } 098 cs.firePostChangeEvent(ce); 099 } 100 } else { 101 _addRenderer(renderer); 102 } 103 } 104 105 protected void _addRenderer(SequenceRenderer renderer) { 106 renderers.add(renderer); 107 } 108 109 /** 110 * <code>removeRenderer</code> removes a renderer. 111 * 112 * @param renderer a <code>SequenceRenderer</code> to remove. 113 * 114 * @exception ChangeVetoException if the renderer can not be 115 * removed. 116 */ 117 public void removeRenderer(SequenceRenderer renderer) 118 throws ChangeVetoException { 119 if (hasListeners()) { 120 ChangeEvent ce = new ChangeEvent(this, RENDERERS, null, renderer); 121 ChangeSupport cs = getChangeSupport(RENDERERS); 122 123 synchronized(cs) { 124 cs.firePreChangeEvent(ce); 125 _removeRenderer(renderer); 126 if (renderer instanceof Changeable) { 127 Changeable c = (Changeable) renderer; 128 c.removeChangeListener(rendererForwarder, 129 SequenceRenderContext.REPAINT); 130 } 131 cs.firePostChangeEvent(ce); 132 } 133 } else { 134 _removeRenderer(renderer); 135 } 136 } 137 138 protected void _removeRenderer(SequenceRenderer renderer) { 139 renderers.remove(renderer); 140 } 141 142 /** 143 * <code>clearRenderers</code> removes all renderers from this 144 * renderer. 145 * 146 * @exception ChangeVetoException if the renderers can not be 147 * cleared. 148 */ 149 public void clearRenderers() 150 throws ChangeVetoException { 151 if (hasListeners()) { 152 ChangeEvent ce = new ChangeEvent(this, RENDERERS); 153 ChangeSupport cs = getChangeSupport(RENDERERS); 154 155 synchronized(cs) { 156 cs.firePreChangeEvent(ce); 157 for (Iterator i = renderers.iterator(); i.hasNext(); ) { 158 Object r = i.next(); 159 if (r instanceof Changeable) { 160 Changeable c = (Changeable) r; 161 c.removeChangeListener(rendererForwarder, 162 SequenceRenderContext.REPAINT); 163 } 164 } 165 renderers.clear(); 166 cs.firePostChangeEvent(ce); 167 } 168 } else { 169 renderers.clear(); 170 } 171 } 172 173 public double getDepth(SequenceRenderContext src) { 174 return LayeredRenderer.INSTANCE.getDepth(Collections.nCopies(renderers.size(), src), 175 renderers); 176 } 177 178 public double getMinimumLeader(SequenceRenderContext src) { 179 return LayeredRenderer.INSTANCE.getMinimumLeader(Collections.nCopies(renderers.size(), src), 180 renderers); 181 } 182 183 public double getMinimumTrailer(SequenceRenderContext src) { 184 return LayeredRenderer.INSTANCE.getMinimumTrailer(Collections.nCopies(renderers.size(), src), 185 renderers); 186 } 187 188 public void paint(Graphics2D g, SequenceRenderContext src) { 189 LayeredRenderer.INSTANCE.paint(g, 190 Collections.nCopies(renderers.size(), src), 191 renderers); 192 } 193 194 public SequenceViewerEvent processMouseEvent(SequenceRenderContext src, 195 MouseEvent me, 196 List path) { 197 path.add(this); 198 SequenceViewerEvent sve = 199 LayeredRenderer.INSTANCE.processMouseEvent(Collections.nCopies(renderers.size(), src), 200 me, 201 path, 202 renderers); 203 204 if (sve == null) { 205 sve = new SequenceViewerEvent(this, 206 null, 207 src.graphicsToSequence(me.getPoint()), 208 me, 209 path); 210 } 211 212 return sve; 213 } 214}