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.BorderLayout; 033import java.awt.Dimension; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.awt.geom.AffineTransform; 037 038import javax.swing.JComboBox; 039import javax.swing.JFrame; 040import javax.swing.JLabel; 041import javax.swing.JPanel; 042import javax.swing.JScrollPane; 043import javax.swing.JSlider; 044import javax.swing.JSpinner; 045import javax.swing.JSplitPane; 046import javax.swing.JToolBar; 047import javax.swing.SpinnerNumberModel; 048import javax.swing.SwingUtilities; 049import javax.swing.event.ChangeEvent; 050import javax.swing.event.ChangeListener; 051 052public class VizApplication { 053 054 private JFrame _mainFrame; 055 private JPanel _mainPanel; 056 private boolean _exitOnClose; 057 058 private SequenceCollection _sequenceCollection; 059 private SiteCollection _siteCollection; 060 061 private OverviewPanel _overviewPanel; 062 private DetailPanel _detailPanel; 063 private SitesPanel _sitesPanel; 064 065 private JSlider _sliderOverall; 066 private JSlider _sliderPerSequence; 067 068 public VizApplication(boolean exitOnClose) { 069 _exitOnClose = exitOnClose; 070 } 071 072 public void show(Sequence[] sequences) { 073 JFrame.setDefaultLookAndFeelDecorated(true); 074 _mainFrame = new JFrame("PIW Visualization Frame"); 075 _mainPanel = new JPanel(new BorderLayout()); 076 _mainFrame.getContentPane().add(_mainPanel); 077 if (_exitOnClose) { 078 _mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 079 } 080 081 // Create sequence collection. 082 this._sequenceCollection = new SequenceCollection(sequences); 083 084 // Create site collection. 085 this._siteCollection = new SiteCollection(this._sequenceCollection); 086 087 // Create the overview panel. 088 this._overviewPanel = new OverviewPanel(this._sequenceCollection, 089 this._siteCollection, new ListenerViewPortMove(), 090 new ListenerSequenceMove()); 091 092 // Create the detail panel. 093 this._detailPanel = new DetailPanel(this._sequenceCollection, 094 this._siteCollection, new ListenerViewPortSize()); 095 096 // Create the transcription factor binding sites panel. 097 this._sitesPanel = new SitesPanel(this._sequenceCollection, 098 this._siteCollection, new ListenerSiteChange()); 099 100 // Create the split panes. 101 JSplitPane splitPaneRight = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 102 new JScrollPane(_overviewPanel), new JScrollPane(_detailPanel)); 103 104 JSplitPane splitPaneMain = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 105 new JScrollPane(_sitesPanel), splitPaneRight); 106 107 // Create toolbar. 108 JToolBar toolbar = new JToolBar(); 109 110 // Add to it the zoom combo box. 111 String[] listResolutions = new String[] { "100%", "200%", "300%" }; 112 JComboBox comboBox = new JComboBox(listResolutions); 113 comboBox.setEditable(true); 114 comboBox.addActionListener(new ListenerComboBox()); 115 comboBox.setMaximumSize(new Dimension(50, 50)); 116 toolbar.add(comboBox); 117 118 // Add spinner for minimum consensus length. 119 JSpinner spinner = new JSpinner(new SpinnerNumberModel(6, 1, 100, 1)); 120 _sequenceCollection.setMinimumConsensusLength(6); 121 spinner.addChangeListener(new ListenerConsensusLength()); 122 spinner.setMaximumSize(new Dimension(100, 50)); 123 toolbar.add(spinner); 124 125 // Add a separator. 126 toolbar.add(new JToolBar.Separator()); 127 128 // Add the overall frequency slider. 129 JLabel label = new JLabel("OF:"); 130 label 131 .setToolTipText("Minimum frequency overall: total occurrence / total number of sites."); 132 toolbar.add(label); 133 134 _sliderOverall = new JSlider(0, (int) Math.ceil(_siteCollection 135 .getMaxFrequencyOverall() * 100), 0); 136 _sliderOverall.setMajorTickSpacing(5); 137 _sliderOverall.setMinorTickSpacing(1); 138 _sliderOverall.setSnapToTicks(true); 139 _sliderOverall.setPaintTicks(true); 140 _sliderOverall.setPaintTrack(true); 141 _sliderOverall.setToolTipText("0"); 142 _sliderOverall.addChangeListener(new ListenerFrequency()); 143 toolbar.add(_sliderOverall); 144 145 // Add a separator. 146 toolbar.add(new JToolBar.Separator()); 147 148 // Add the per sequence frequency slider. 149 label = new JLabel("SF:"); 150 label 151 .setToolTipText("Minimum frequency per sequence: total occurrence per sequence / total number of sites per sequence."); 152 toolbar.add(label); 153 154 _sliderPerSequence = new JSlider(0, (int) Math.ceil(_siteCollection 155 .getMaxFrequencyPerSequence() * 100), 0); 156 _sliderPerSequence.setMajorTickSpacing(5); 157 _sliderPerSequence.setMinorTickSpacing(1); 158 _sliderPerSequence.setSnapToTicks(true); 159 _sliderPerSequence.setPaintTicks(true); 160 _sliderPerSequence.setPaintTrack(true); 161 _sliderPerSequence.setToolTipText("0"); 162 _sliderPerSequence.addChangeListener(new ListenerFrequency()); 163 toolbar.add(_sliderPerSequence); 164 165 // Add toolbar and main panel. 166 _mainPanel.add(toolbar, BorderLayout.NORTH); 167 _mainPanel.add(splitPaneMain, BorderLayout.CENTER); 168 169 // Draw it all. 170 this._overviewPanel.drawSequences(); 171 this._detailPanel.drawSequences(0); 172 173 // Show. 174 _mainFrame.setSize(600, 400); 175 _mainFrame.setVisible(true); 176 177 // Set divider sizes, which only have effect when the windows are shown. 178 splitPaneRight.setDividerLocation(0.7f); 179 splitPaneMain.setDividerLocation(0.3f); 180 } 181 182 private class ListenerConsensusLength implements ChangeListener { 183 /** 184 * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent) 185 */ 186 public void stateChanged(ChangeEvent e) { 187 JSpinner spinner = (JSpinner) e.getSource(); 188 Integer value = (Integer) spinner.getValue(); 189 190 _sequenceCollection.setMinimumConsensusLength(value.intValue()); 191 _overviewPanel.drawSequences(); 192 _detailPanel.drawSequences(); 193 } 194 } 195 196 private class ListenerFrequency implements ChangeListener { 197 public void stateChanged(ChangeEvent e) { 198 JSlider slider = (JSlider) e.getSource(); 199 slider.setToolTipText("" + slider.getValue()); 200 201 _siteCollection.selectAll(); 202 _siteCollection 203 .deselectSitesWithOverallFrequencyUnder(_sliderOverall 204 .getValue() / 100.0); 205 _siteCollection 206 .deselectSitesWithPerSequenceFrequencyUnder(_sliderPerSequence 207 .getValue() / 100.0); 208 _overviewPanel.drawSequences(); 209 _detailPanel.drawSequences(); 210 _sitesPanel.repaint(); 211 } 212 } 213 214 private class ListenerSiteChange implements ActionListener { 215 public void actionPerformed(ActionEvent e) { 216 _overviewPanel.drawSequences(); 217 _detailPanel.drawSequences(); 218 } 219 } 220 221 private class ListenerComboBox implements ActionListener { 222 private int _zoomPrevious; 223 224 public ListenerComboBox() { 225 _zoomPrevious = 100; 226 } 227 228 public void actionPerformed(ActionEvent e) { 229 JComboBox cb = (JComboBox) e.getSource(); 230 String newSelection = (String) cb.getSelectedItem(); 231 232 newSelection = newSelection.trim(); 233 234 if (newSelection.endsWith("%")) { 235 newSelection = newSelection.substring(0, 236 newSelection.length() - 1); 237 } 238 239 // Try to format this number. 240 Integer zoom; 241 try { 242 zoom = new Integer(newSelection); 243 } catch (NumberFormatException ex) { 244 zoom = new Integer(_zoomPrevious); 245 } 246 247 newSelection += "%"; 248 cb.setSelectedItem(newSelection); 249 250 // Zoom the canvas and set its preferred size. 251 AffineTransform current = _overviewPanel.getCanvasPane() 252 .getTransformContext().getTransform(); 253 current.setToIdentity(); 254 double factor = ((double) zoom.intValue()) / 100; 255 current.scale(factor, factor); 256 _overviewPanel.getCanvasPane().setTransform(current); 257 258 // Ask the canvas to recalculate its preferred size. 259 _overviewPanel.setPreferredSize(); 260 261 _mainPanel.repaint(); 262 } 263 } 264 265 private class ListenerViewPortSize implements ActionListener { 266 public void actionPerformed(ActionEvent e) { 267 _overviewPanel.setViewPortSize(e.getID()); 268 _detailPanel.drawSequences(); 269 } 270 } 271 272 private class ListenerSequenceMove implements ActionListener { 273 /** 274 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) 275 */ 276 public void actionPerformed(ActionEvent e) { 277 // Hacked up fields in ActionEvent. 278 int offset = e.getID(); 279 int index = e.getModifiers(); 280 281 _sequenceCollection.setOffset(index, offset); 282 _overviewPanel.drawSequences(); 283 _detailPanel.drawSequences(); 284 } 285 } 286 287 private class ListenerViewPortMove implements ActionListener { 288 public void actionPerformed(ActionEvent e) { 289 _detailPanel.drawSequences(e.getID()); 290 } 291 } 292 293 /** 294 * Main function 295 */ 296 public static void main(String argv[]) { 297 // Always invoke graphics code in the event thread. 298 SwingUtilities.invokeLater(new Runnable() { 299 public void run() { 300 301 // Create an array of Sequence objects. 302 Sequence[] sequences = new Sequence[] { 303 new Sequence( 304 "acc1", 305 "gene1", 306 "ctagggggggggggataaaaaaactactatatagagatctacccatcacc", 307 new TranscriptionFactorBindingSite[] { 308 new TranscriptionFactorBindingSite( 309 "tfbs1", 25), 310 new TranscriptionFactorBindingSite( 311 "tfbs2", -5), 312 new TranscriptionFactorBindingSite( 313 "tfbs3", 5) }), 314 new Sequence( 315 "acc1", 316 "gene1", 317 "ctagggggggggggataaaagggggactatatagagatctacccatcacc", 318 new TranscriptionFactorBindingSite[] { 319 new TranscriptionFactorBindingSite( 320 "tfbs1", 5), 321 new TranscriptionFactorBindingSite( 322 "tfbs2", -5), 323 new TranscriptionFactorBindingSite( 324 "tfbs3", 25) }), 325 new Sequence( 326 "acc1", 327 "gene1", 328 "ctagggggggggggataaaaaaactactatatagagatccccccatcacc", 329 new TranscriptionFactorBindingSite[] { 330 new TranscriptionFactorBindingSite( 331 "tfbs1", 5), 332 new TranscriptionFactorBindingSite( 333 "tfbs2", -5), 334 new TranscriptionFactorBindingSite( 335 "tfbs3", 25) }) }; 336 337 VizApplication app = new VizApplication(true); 338 app.show(sequences); 339 } 340 }); 341 } 342} 343 344// vim: et ts=4 sw=4