Update mussa to build on ubuntu 10.04 with qt 4.6.2 +boost 1.40.0.1
[mussa.git] / qui / MussaAlignedWindow.cpp
1 #include <list>
2 #include <vector>
3 #include <sstream>
4
5 #include <QStatusBar>
6 #include <QString>
7 #include <QMenuBar>
8
9 #include "qui/MussaAlignedWindow.hpp"
10 #include "alg/sequence.hpp"
11
12 #include <iostream>
13 using namespace std;
14
15 MussaAlignedWindow::MussaAlignedWindow(MussaRef m,
16                                        boost::shared_ptr<QDir> default_dir_,
17                                        const set<int>& sel_paths,
18                                        SubanalysisWindowRef window, 
19                                        QWidget *parent)
20   : QMainWindow(parent),
21     analysis(m),
22     default_dir(default_dir_),
23     subanalysis_window(window),
24     browser(default_dir),
25     pick_align_menu(tr("Choose Alignment")),
26     view_align_menu(tr("View Alignment")),
27     threshold_widget(0),
28     zoom(0),
29     alignTB(0)
30 {
31   setupActions();
32   connect(&browser, SIGNAL(basepairsCopied(size_t)), 
33           this, SLOT(showBasePairsCopied(size_t)));
34   browser.setSequences(analysis->sequences(), analysis->colorMapper());
35   setSelectedPaths(analysis, sel_paths);
36   setAlignment(0);
37   double zoom_level = browser.zoomToSequence();
38
39   zoom = new ZoomWidget();
40   connect(zoom, SIGNAL(valueChanged(double)), 
41           &browser, SLOT(setZoom(double)));
42   zoom->setValue(zoom_level);
43   
44   // Mouse scroll wheel zooming!
45   connect(&browser, SIGNAL(mouseWheelZoom(double)),
46                   zoom, SLOT(setValue(double)));
47   
48   computeMatchLines();
49   setupMenus();
50   setupAlignmentMenus();
51   
52   setCentralWidget(&browser);
53
54   // Add a threhold widget set to our current threshold and make it readonly 
55   threshold_widget = new ThresholdWidget;
56   threshold_widget->setRange(analysis->get_threshold(),analysis->get_window());
57   threshold_widget->setBasepairThreshold(analysis->get_soft_threshold());
58   threshold_widget->setReadOnly(true);
59   
60   alignTB = new QToolBar();
61   alignTB->addWidget(zoom);
62   alignTB->addWidget(threshold_widget);
63   addToolBar(alignTB);
64   
65   ostringstream message;
66   message << "Selected " << selected_paths.size() << " paths";
67   statusBar()->showMessage(message.str().c_str(), 5000);
68   browser.updatePosition();
69   
70   updateTitle();
71 }
72
73 void MussaAlignedWindow::setupActions()
74 {
75   // more cut-n-paste from MussaWindow
76   createSubAnalysisAction = new QAction(tr("Add to Subanalysis"), this);
77   connect(createSubAnalysisAction, SIGNAL(triggered()), 
78           this, SLOT(createSubAnalysis()));
79             
80   //Save pixel map action
81   saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
82   connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
83           &browser, SLOT(promptSaveBrowserPixmap()));
84   saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
85 }
86
87 void MussaAlignedWindow::setupMenus()
88 {
89   QMenu *newMenu = menuBar()->addMenu(tr("&File"));
90   newMenu->addAction(saveBrowserPixmapAction);
91
92   newMenu = menuBar()->addMenu(tr("&Edit"));
93   newMenu->addAction(browser.getCopySelectedSequenceAsStringAction());
94   newMenu->addAction(browser.getCopySelectedSequenceAsFastaAction());
95   newMenu->addAction(createSubAnalysisAction);
96   
97   // add some extra features to the context menu
98   QMenu *popupMenu = browser.getPopupMenu();
99   if (popupMenu) {
100     popupMenu->addAction(createSubAnalysisAction);
101   }  
102 }
103
104 void MussaAlignedWindow::setupAlignmentMenus()
105 {
106   pick_align_menu.clear();
107   view_align_menu.clear();
108   pick_actions.clear();
109   view_actions.clear();
110
111   for(vector<ConservedPath >::iterator pathz_i=selected_paths.begin(); 
112       pathz_i != selected_paths.end(); 
113       ++pathz_i)
114   {
115     ConservedPath::path_type normalized_path = pathz_i->normalizedIndexes();
116     ostringstream menu_text;
117     menu_text << pathz_i->window_size << ":";
118     ConservedPath::iterator element_i = normalized_path.begin();
119     menu_text << *element_i++;
120     for (;
121          element_i != normalized_path.end();
122          ++element_i)
123     {
124       menu_text << ", ";
125       menu_text << *element_i;
126     }
127     int index = pathz_i - selected_paths.begin();
128     IntAction *pick = new IntAction(QString(menu_text.str().c_str()), index, this);
129     connect(pick, SIGNAL(triggered(int)), this, SLOT(setAlignment(int)));
130     pick_actions.push_back(pick);
131     pick_align_menu.addAction(pick);
132     IntAction *view = new IntAction(QString(menu_text.str().c_str()), index, this);
133     connect(view, SIGNAL(triggered(int)), this, SLOT(toggleViewAlignment(int)));
134     view->setCheckable(true);
135     view->setChecked(true);
136     view_actions.push_back(view);
137     view_align_menu.addAction(view);
138   }
139
140   menuBar()->addMenu(&pick_align_menu);
141   menuBar()->addMenu(&view_align_menu);
142 }
143
144
145 void MussaAlignedWindow::setSelectedPaths(MussaRef m, const set<int>& sel_paths)
146 {
147   // sets are sorted
148   set<int>::iterator sel_i = sel_paths.begin();
149   list<ConservedPath>::const_iterator path_i = m->paths().refined_pathz.begin();
150   list<ConservedPath>::const_iterator path_end = m->paths().refined_pathz.end();
151   size_t path_size = m->paths().refined_pathz.size();
152   size_t pathid=0;
153
154   selected_paths.reserve(sel_paths.size());
155   view_paths.reserve(sel_paths.size());
156   while (pathid != path_size and sel_i != sel_paths.end())
157   {
158     assert (*sel_i >= 0);
159     size_t sel_pathid = (size_t)(*sel_i);
160     if (pathid == sel_pathid) {
161       selected_paths.push_back(*path_i);
162       view_paths.push_back(true);
163       ++pathid;
164       ++path_i;
165       ++sel_i;
166     } else if (pathid < sel_pathid) {
167       ++pathid;
168       ++path_i;
169     } else if (pathid > sel_pathid) {
170       ++sel_i;
171     }
172   }
173 }
174
175 // FIXME: this is a cut-n-paste from MussaWindow, perhaps they should be refactored to
176 // some shared place
177 void MussaAlignedWindow::createSubAnalysis()
178 {
179   list<SequenceLocation> result;
180   SequenceLocationModel& model = subanalysis_window->getModel();
181   browser.copySelectedTracksAsSeqLocation(result);
182   for(list<SequenceLocation>::iterator result_itor = result.begin();
183       result_itor != result.end();
184       ++result_itor)
185   {
186     model.push_back(*result_itor);
187   }
188
189   if (not subanalysis_window->isVisible()) {
190     subanalysis_window->show();
191   }
192 }
193
194 void MussaAlignedWindow::setAlignment(int alignment_index)
195 {
196   if (selected_paths.size() > 0) {
197     browser.centerOnPath(selected_paths[alignment_index].normalizedIndexes());
198   }
199 }
200
201 void MussaAlignedWindow::showBasePairsCopied(size_t bp_copied)
202 {
203   QString msg("Copied ");
204   QString num;
205   num.setNum(bp_copied);
206   msg += num + " base pairs";
207   statusBar()->showMessage(msg, 5000);
208 }
209
210 void MussaAlignedWindow::toggleViewAlignment(int alignment_index)
211 {
212   view_paths[alignment_index]= not view_paths[alignment_index]; 
213   // perhaps it'd be better if we could erase specific sets
214   // of matches instead of erasing them all and recomputing them all
215   // but this is easier
216   computeMatchLines();
217 }
218
219 void MussaAlignedWindow::update()
220 {
221   browser.update();
222 }
223
224 void MussaAlignedWindow::updateTitle()
225 {
226   std::string title("Sequence View: ");
227   if (analysis) {
228     title += analysis->get_title();
229   }
230   setWindowTitle(title.c_str());
231 }
232
233 void MussaAlignedWindow::computeMatchLines()
234 {
235   browser.clear_links();
236   
237   // filter out conserved paths
238   list<ConservedPath> filtered_paths;
239   vector<ConservedPath>::iterator path_i = selected_paths.begin();
240   list<ConservedPath::path_type> result;
241   list<vector<bool> > reversed;
242
243   for(vector<ConservedPath>::size_type count = 0; 
244       count != selected_paths.size();
245       ++count, ++path_i)
246   {
247     if (view_paths[count]) 
248       filtered_paths.push_back(*path_i);
249   }
250   analysis->createLocalAlignment(filtered_paths.begin(), 
251                                  filtered_paths.end(),
252                                  result, 
253                                  reversed);
254
255   list<ConservedPath::path_type>::const_iterator result_i = result.begin();
256   list<vector<bool> >::const_iterator reversed_i = reversed.begin();
257   for(int i = 0; i != result.size(); ++i, ++result_i, ++reversed_i)
258   {
259     // make 1 base long links
260     browser.link(*result_i, *reversed_i, 1);
261   }
262 }