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