add prototype wrapping of the qt sequence browser
[mussa.git] / qui / seqbrowser / SequenceBrowserWidget.cpp
1 #include <iostream>
2
3 #include <QLabel>
4 #include <QScrollBar>
5 #include <QSpacerItem>
6 #include <QSplitter>
7 #include <QVBoxLayout>
8 #include <QWidget>
9
10 #include "qui/seqbrowser/SequenceBrowserWidget.hpp"
11 #include "qui/seqbrowser/SequenceBrowser.hpp"
12 #include "qui/seqbrowser/ScrollableSequenceBrowser.hpp"
13 #include "qui/seqbrowser/SequenceDescription.hpp"
14 #include "qui/ImageSaveDialog.hpp"
15
16 #include "alg/glsequence.hpp"
17
18 #include <math.h>
19 using namespace std;
20
21 SequenceBrowserWidget::SequenceBrowserWidget(
22     QWidget *parent)
23   : QScrollArea(parent),
24     left_sidebar(0),
25     scrollable_browser(0),
26     right_sidebar(0),
27     layout(0),
28     layout_container(0)
29 {
30   boost::shared_ptr<QDir> empty_dir(new QDir);
31   default_dir = empty_dir;
32
33   init();
34 }
35
36 SequenceBrowserWidget::SequenceBrowserWidget(
37     boost::shared_ptr<QDir> default_dir_,
38     QWidget *parent
39 )
40   : QScrollArea(parent),
41     left_sidebar(0),
42     scrollable_browser(0),
43     right_sidebar(0),
44     layout(0),
45     layout_container(0)
46 {
47   default_dir = default_dir_;
48
49   init();
50 }
51
52 void SequenceBrowserWidget::init()
53 {
54   layout_container = new QWidget(this);
55   layout = new QHBoxLayout(layout_container);
56   left_sidebar = new SequenceBrowserSidebar(layout_container);
57   scrollable_browser = new ScrollableSequenceBrowser(layout_container);
58   right_sidebar = new SequenceBrowserSidebar(layout_container);
59   
60   layout->addWidget(left_sidebar, 0);
61   layout->addWidget(scrollable_browser, 1);
62   layout->addWidget(right_sidebar, 0);
63   
64   layout_container->setLayout(layout);
65   setWidget(layout_container);
66   setWidgetResizable(true);
67   
68   // update position values when something in the SequenceBrowser changes
69   connect(&(scrollable_browser->browser()), SIGNAL(viewportChanged()),
70           this, SLOT(updatePosition()));
71   connect(&(scrollable_browser->browser()), SIGNAL(basepairsCopied(size_t)),
72           this, SIGNAL(basepairsCopied(size_t)));
73   
74   // Send the signal mouseWheelZoom signal from seq browser upward.
75   connect(&(scrollable_browser->browser()), SIGNAL(mouseWheelZoom(double)),
76           this, SIGNAL(mouseWheelZoom(double)));
77 }
78
79
80 SequenceBrowserWidget::SequenceBrowserWidget(const SequenceBrowserWidget &o)
81   : QScrollArea(o.window()),
82     left_sidebar(o.left_sidebar),
83     scrollable_browser(o.scrollable_browser),
84     right_sidebar(o.right_sidebar),
85     layout(o.layout),
86     layout_container(o.layout_container)
87 {
88 }
89
90 QSize SequenceBrowserWidget::sizeHint() const
91 {
92   // don't trust the layouts size computation
93   // use some heavy handed brute force to compute
94   // the correct size so our stupid scrollable_browser
95   // will show the full viewport.
96   QSize left = left_sidebar->sizeHint();
97   QSize center = scrollable_browser->sizeHint();
98   QSize right = right_sidebar->sizeHint();
99   
100   int width = left.width()+center.width()+right.width();
101   width += 2 * layout->margin();
102   if (layout->spacing() > 0) {
103     width += layout->spacing() * 3;
104   }
105   return QSize(width, center.height());
106 }
107
108 void SequenceBrowserWidget::clear()
109 {
110   converted_sequences.clear();
111   scrollable_browser->browser().clear();
112
113   SequenceBrowserSidebar::collection left = left_sidebar->descriptions;
114   SequenceBrowserSidebar::collection right = right_sidebar->descriptions;
115   for(size_t i = 0; i != left_sidebar->size(); ++i)
116   {
117     disconnect(left[i], SIGNAL(nameChanged(const QString &)),
118                right[i], SLOT(setName(const QString &)));
119     disconnect(right[i], SIGNAL(nameChanged(const QString &)),
120                left[i], SLOT(setName(const QString &)));
121   }
122   left_sidebar->clear();
123   right_sidebar->clear();
124 }
125
126 QMenu *SequenceBrowserWidget::getPopupMenu()
127 {
128   return scrollable_browser->browser().getPopupMenu();
129 }
130
131 QAction *SequenceBrowserWidget::getCopySelectedSequenceAsStringAction()
132 {
133   return scrollable_browser->browser().getCopySelectedSequenceAsStringAction();
134 }
135
136 QAction *SequenceBrowserWidget::getCopySelectedSequenceAsFastaAction()
137 {
138   return scrollable_browser->browser().getCopySelectedSequenceAsFastaAction();
139 }
140
141 QAction *SequenceBrowserWidget::getEditSequencePropertiesAction()
142 {
143   return scrollable_browser->browser().getEditSequencePropertiesAction();
144 }
145
146 void SequenceBrowserWidget::copySelectedSequenceAsFasta()
147 {
148   scrollable_browser->browser().copySelectedSequenceAsFasta();
149 }
150
151 void SequenceBrowserWidget::copySelectedTracksAsSeqLocation(
152     std::list<SequenceLocation>& locations
153 )
154 {
155   scrollable_browser->browser().copySelectedTracksAsSeqLocation(locations);
156 }
157
158 void SequenceBrowserWidget::setSequences(
159     const std::vector<SequenceRef >& new_sequences,
160     AnnotationColorsRef cm)
161 {
162   SequenceBrowser& browser = scrollable_browser->browser();
163   clear();
164   for(Mussa::vector_sequence_type::const_iterator seq_i = new_sequences.begin();
165       seq_i != new_sequences.end();
166       ++seq_i)
167   {
168     // Blech *(*seq_i) is dereferencing the shared_ptr stored in the iterator.
169     boost::shared_ptr<GlSequence> gs(new GlSequence(*seq_i, cm));
170     converted_sequences.push_back(gs);
171     browser.push_sequence(gs);
172   }
173   left_sidebar->setSequences(converted_sequences);
174   right_sidebar->setSequences(converted_sequences);
175
176   // connect the text change signals to each other
177   SequenceBrowserSidebar::collection left = left_sidebar->descriptions;
178   SequenceBrowserSidebar::collection right = right_sidebar->descriptions;
179   for(size_t i = 0; i != new_sequences.size() and i != right.size(); ++i)
180   {
181     connect(left[i], SIGNAL(nameChanged(const QString &)),
182             right[i], SLOT(setName(const QString &)));
183     connect(right[i], SIGNAL(nameChanged(const QString &)),
184             left[i], SLOT(setName(const QString &)));
185   }
186
187   updatePosition();
188 }
189
190 void SequenceBrowserWidget::setSequences(
191   std::vector<boost::shared_ptr<GlSequence> >& sequences
192 )
193 {
194   SequenceBrowser& browser = scrollable_browser->browser();
195   clear();
196   for(vector<boost::shared_ptr<GlSequence> >::iterator seq_i = sequences.begin();
197       seq_i != sequences.end();
198       ++seq_i)
199   {
200     browser.push_sequence(*seq_i);
201   }
202   left_sidebar->setSequences(sequences);
203   right_sidebar->setSequences(sequences);
204   updatePosition();
205 }
206
207 const vector<boost::shared_ptr<GlSequence> >& SequenceBrowserWidget::sequences() const
208 {
209   return scrollable_browser->browser().sequences();
210 }
211
212 void SequenceBrowserWidget::clear_links()
213 {
214   scrollable_browser->browser().clear_links();
215 }
216
217 void SequenceBrowserWidget::link(const std::vector<int>& path, 
218                                  const std::vector<bool>& isRC, 
219                                  int length)
220 {
221   scrollable_browser->browser().link(path, isRC, length);
222   scrollable_browser->browser().update();
223 }
224
225 const std::set<int> SequenceBrowserWidget::selectedPaths() const
226 {
227   return scrollable_browser->browser().selectedPaths();
228 }
229
230 void SequenceBrowserWidget::centerOnPath(const vector<int>& paths)
231 {
232   scrollable_browser->browser().centerOnPath(paths);
233   updatePosition();
234 }
235
236 /* This could theoretically be pushed down to some set 
237  * of signals and slots connecting SequenceDescriptions and 
238  * some signal emitted by the browser's viewportChanged code
239  * but evertime I tried to figure it out, I got confused about 
240  * how the descriptions in one of the sidebars was supposed to know
241  * if it was mapping the rightbase or the leftbase.
242  * And so though this could be better the typical use cases 
243  * can just talk to the SequenceBrowserWidget for rendering
244  * or mussa output
245  */
246 void SequenceBrowserWidget::updatePosition()
247 {
248   const SequenceBrowser& browser = scrollable_browser->browser();
249   const vector<boost::shared_ptr<GlSequence> > &sequences = browser.sequences();
250   SequenceBrowserSidebar::collection left = left_sidebar->descriptions;
251   SequenceBrowserSidebar::collection right = right_sidebar->descriptions;
252   for(size_t i = 0; i != sequences.size() and i != right.size(); ++i)
253   {
254     left[i]->setPosition(sequences[i]->leftbase(browser.viewportLeft()));
255     right[i]->setPosition(sequences[i]->rightbase(browser.viewportRight()));
256   }
257   scrollable_browser->browser().update();
258   scrollable_browser->updateScrollBar();
259 }
260
261 void SequenceBrowserWidget::promptSaveBrowserPixmap()
262 {
263   QSize size;
264   size = scrollable_browser->browser().size();
265   //Image Save Dialog
266   ImageSaveDialog imageSaveDialog(default_dir, scrollable_browser, this);
267   imageSaveDialog.setSize(size.width(), size.height());
268   imageSaveDialog.exec();
269 }
270
271 double SequenceBrowserWidget::zoom()
272 {
273   return scrollable_browser->browser().zoom();
274 }
275
276 double SequenceBrowserWidget::zoomOut()
277 {
278   double zoom_level = scrollable_browser->browser().zoomOut();
279   scrollable_browser->updateScrollBar();
280   return zoom_level;
281 }
282
283 double SequenceBrowserWidget::zoomToSequence()
284 {
285   double zoom_level = scrollable_browser->browser().zoomToSequence();
286   scrollable_browser->updateScrollBar();
287   return zoom_level;
288 }
289
290 void SequenceBrowserWidget::setZoom(double z)
291 {
292   scrollable_browser->browser().setZoom(z);
293 }
294
295 void SequenceBrowserWidget::update()
296 {
297   QWidget::update();
298   scrollable_browser->browser().update();
299 }