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