001/* 002 * Copyright (c) 2004-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.sdm.spa.actors.piw.viz; 031 032import java.awt.AlphaComposite; 033import java.awt.Color; 034import java.awt.Dimension; 035import java.awt.Font; 036import java.awt.Graphics2D; 037import java.awt.Rectangle; 038import java.awt.event.ActionEvent; 039import java.awt.event.ActionListener; 040import java.awt.geom.AffineTransform; 041 042import javax.swing.SwingConstants; 043 044import diva.canvas.CompositeFigure; 045import diva.canvas.Figure; 046import diva.canvas.FigureLayer; 047import diva.canvas.GraphicsPane; 048import diva.canvas.JCanvas; 049import diva.canvas.event.LayerEvent; 050import diva.canvas.event.MouseFilter; 051import diva.canvas.interactor.DragInteractor; 052import diva.canvas.interactor.Interactor; 053import diva.canvas.toolbox.BasicRectangle; 054import diva.canvas.toolbox.LabelFigure; 055 056public class OverviewPanel extends JCanvas { 057 058 private static final long serialVersionUID = 3257288041205608504L; 059 private final ActionListener _listenerViewPortMove; 060 private final ActionListener _listenerSequenceMove; 061 private Figure _viewPort; 062 private int _sizeViewPort; 063 064 private final SequenceCollection _sequenceCollection; 065 private final SiteCollection _siteCollection; 066 067 public OverviewPanel(SequenceCollection sequenceCollection, 068 SiteCollection siteCollection, ActionListener listenerViewPortMove, 069 ActionListener listenerSequenceMove) { 070 071 this._listenerViewPortMove = listenerViewPortMove; 072 this._listenerSequenceMove = listenerSequenceMove; 073 this._sizeViewPort = 100; 074 075 this._sequenceCollection = sequenceCollection; 076 this._siteCollection = siteCollection; 077 } 078 079 public void setPreferredSize() { 080 int width = _sequenceCollection.getMaximumSequenceLength() + 200; 081 int height = (_sequenceCollection.size() + 2) * 50; 082 083 AffineTransform current = this.getCanvasPane().getTransformContext() 084 .getTransform(); 085 width *= current.getScaleX(); 086 height *= current.getScaleY(); 087 088 this.setPreferredSize(new Dimension(width, height)); 089 } 090 091 private void setViewPortSize(int height, int maxDrag) { 092 int size = 100; 093 int start = 150; 094 095 if (null != _viewPort) { 096 size = (int) _viewPort.getShape().getBounds().getWidth(); 097 start = (int) _viewPort.getShape().getBounds().getX(); 098 } 099 100 setViewPortSize(size, start, height, maxDrag); 101 } 102 103 private void setViewPortSize(int size, int start, int height, int maxDrag) { 104 FigureLayer layer = ((GraphicsPane) this.getCanvasPane()) 105 .getForegroundLayer(); 106 107 // Create anew. 108 BasicRectangle newViewPort = new BasicRectangle(start, 25, 109 _sizeViewPort, height, Color.MAGENTA) { 110 public void paint(Graphics2D g) { 111 AlphaComposite c = AlphaComposite.getInstance( 112 AlphaComposite.SRC_OVER, 0.1f); 113 g.setComposite(c); 114 g.setPaint(new Color(150, 50, 150)); 115 g.fill(this.getShape()); 116 g.setComposite(AlphaComposite.SrcOver); 117 } 118 }; 119 newViewPort.setInteractor(new DraggerSnap(_listenerViewPortMove, 10, 120 150, maxDrag)); 121 122 // If _viewPort exists, then remove it. 123 if (null != _viewPort) { 124 // Need to make sure the new viewport is inserted 125 // at the same zlayer as the previous. 126 int index = layer.getFigures().indexOf(_viewPort); 127 if (-1 == index) { 128 layer.add(newViewPort); 129 } else { 130 layer.add(index, newViewPort); 131 layer.remove(_viewPort); 132 } 133 } else { 134 layer.add(newViewPort); 135 } 136 137 _viewPort = newViewPort; 138 } 139 140 public void setViewPortSize(int size) { 141 142 // If the input is non-positive, then set the size to 1. 143 if (0 >= size) { 144 this._sizeViewPort = 1; 145 } else { 146 this._sizeViewPort = size; 147 } 148 149 int start = 150; 150 int height = 100; 151 int maxDrag = 500; 152 153 if (null != _viewPort) { 154 start = (int) _viewPort.getShape().getBounds().getX(); 155 height = (int) _viewPort.getShape().getBounds().getHeight(); 156 maxDrag = ((DraggerSnap) _viewPort.getInteractor())._maximum; 157 } 158 159 setViewPortSize(this._sizeViewPort, start, height, maxDrag); 160 } 161 162 private void drawStartEndMarkers(Sequence sequence, 163 CompositeFigure compositeFigure, int y) { 164 LabelFigure start = new LabelFigure("1", "SansSerif", Font.PLAIN, 10); 165 LabelFigure end = new LabelFigure(new Integer(sequence.lengthNoGaps()) 166 .toString(), "SansSerif", Font.PLAIN, 10); 167 start.translateTo(0, y); 168 end.translateTo(sequence.alignedSequence.length() - 1, y); 169 compositeFigure.add(start); 170 compositeFigure.add(end); 171 } 172 173 private void drawSequence(String strSequence, 174 CompositeFigure compositeFigure, int y, int height, Color color, 175 boolean isConsensus) { 176 177 String loopSequence = strSequence; 178 int loopSpot = 0; 179 while (loopSequence.length() > 0) { 180 int length = loopSequence.length(); 181 if (loopSequence.charAt(0) == '-') { 182 loopSequence = loopSequence.replaceFirst("-+", ""); 183 length -= loopSequence.length(); 184 } else { 185 loopSequence = loopSequence.replaceFirst("[^-]+", ""); 186 length -= loopSequence.length(); 187 188 if (isConsensus 189 && length < _sequenceCollection 190 .getMinimumConsensusLength()) { 191 continue; 192 } 193 194 compositeFigure.add(new BasicRectangle(loopSpot, y, length, 195 height, color, 0)); 196 } 197 loopSpot += length; 198 } 199 } 200 201 public void drawSequences() { 202 FigureLayer layer = ((GraphicsPane) this.getCanvasPane()) 203 .getForegroundLayer(); 204 205 // Clear whatever's been drawn before. 206 layer.clear(); 207 208 // Draw consensus sequence. 209 CompositeFigure compositeFigure = new CompositeFigure(); 210 drawSequence(_sequenceCollection.getConsensus(), compositeFigure, 0, 211 _sequenceCollection.size() * 50, Color.LIGHT_GRAY, true); 212 compositeFigure.translate(150, 25); 213 layer.add(compositeFigure); 214 215 // Set the preferred size and draw the viewport. 216 this.setPreferredSize(); 217 this.setViewPortSize(_sequenceCollection.size() * 50, 218 _sequenceCollection.getConsensus().length() + 150); 219 220 for (int i = 0; i < _sequenceCollection.size(); i++) { 221 Sequence seq = _sequenceCollection.getSequence(i); 222 223 Interactor boundedDragger = new DraggerSnapSequence( 224 _listenerSequenceMove, 1, 148, _sequenceCollection 225 .getConsensus().length() + 150 - 1); 226 boundedDragger.setMouseFilter(MouseFilter.defaultFilter); 227 228 // Add the label for accession number. 229 LabelFigure labelFigure = new LabelFigure( 230 seq.accessionNumberOriginal, "SansSerif", Font.PLAIN, 14); 231 labelFigure.setFillPaint(Color.BLUE); 232 labelFigure.translateTo(20, (i + 1) * 50); 233 labelFigure.setAnchor(SwingConstants.SOUTH_WEST); 234 layer.add(labelFigure); 235 236 // Add the label for gene ID. 237 labelFigure = new LabelFigure(seq.geneID, "SansSerif", Font.ITALIC, 238 14); 239 labelFigure.translateTo(20, (i + 1) * 50); 240 labelFigure.setAnchor(SwingConstants.NORTH_WEST); 241 layer.add(labelFigure); 242 243 // Draw the sequence. 244 compositeFigure = new CompositeFigure(); 245 drawSequence(seq.alignedSequence, compositeFigure, 0, 1, 246 Color.DARK_GRAY, false); 247 drawStartEndMarkers(seq, compositeFigure, 15); 248 249 // Draw the transcription factor binding sites. 250 for (int j = 0; j < seq.arrTFBSs.length; j++) { 251 final TranscriptionFactorBindingSite tfbs = seq.arrTFBSs[j]; 252 final SiteCollection.Site site = _siteCollection 253 .getSite(tfbs.name); 254 // If not visible, then don't paint. 255 if (!site.selected) { 256 continue; 257 } 258 259 // Get the y. 260 int y = 4; 261 if (tfbs.location < 0) { 262 y = -4; 263 } 264 265 compositeFigure.add(new BasicRectangle(Math.abs(tfbs.location), 266 y, 10, 4) { 267 public void paint(Graphics2D g) { 268 AlphaComposite c = AlphaComposite.getInstance( 269 AlphaComposite.SRC_OVER, 0.3f); 270 g.setComposite(c); 271 g.setPaint(site.color); 272 g.fill(this.getShape()); 273 g.setComposite(AlphaComposite.SrcOver); 274 } 275 }); 276 } 277 278 compositeFigure.translate(150 + seq.offset, (i + 1) * 50); 279 compositeFigure.setInteractor(boundedDragger); 280 layer.add(compositeFigure); 281 } 282 } 283 284 class DraggerSnap extends DragInteractor { 285 private double _remainderX = 0; 286 protected final ActionListener _listener; 287 public final double _step; 288 public final int _minimum; 289 public final int _maximum; 290 291 protected DraggerSnap(ActionListener listener, double step, 292 int minimum, int maximum) { 293 this._listener = listener; 294 this._step = step; 295 this._minimum = minimum; 296 this._maximum = maximum; 297 } 298 299 public void translate(LayerEvent e, double x, double y) { 300 _remainderX += x; 301 302 double translateX = ((int) ((_remainderX + _step / 2) / _step)) 303 * _step; 304 _remainderX -= translateX; 305 306 double figureX = e.getFigureSource().getShape().getBounds().getX(); 307 308 // If this puts us negative, then stop. 309 if (figureX + translateX < _minimum) { 310 translateX = -(((int) (figureX - _minimum) / _step) * _step); 311 } 312 313 // If this puts us past max, then to up to it. 314 if (figureX + translateX > _maximum) { 315 translateX = (((int) (_maximum - figureX)) / _step) * _step; 316 } 317 318 super.translate(e, translateX, 0); 319 } 320 321 public void mouseReleased(LayerEvent e) { 322 if (null != _listener) { 323 _listener.actionPerformed(new ActionEvent(this, (int) e 324 .getFigureSource().getShape().getBounds().getX() 325 - _minimum, "ViewPort move")); 326 } 327 } 328 } 329 330 class DraggerSnapSequence extends DraggerSnap { 331 332 protected DraggerSnapSequence(ActionListener listener, double step, 333 int minimum, int maximum) { 334 335 super(listener, step, minimum, maximum); 336 } 337 338 public void mouseReleased(LayerEvent e) { 339 if (null != _listener) { 340 Rectangle r = e.getFigureSource().getShape().getBounds(); 341 _listener 342 .actionPerformed(new ActionEvent(this, (int) r.getX() 343 - _minimum, "Sequence move", 344 ((int) r.getY() - 20) / 50)); 345 } 346 } 347 } 348}