Allow MussaAlignedWindows to create subanalyses
[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                                        const set<int>& sel_paths,
17                                        SubanalysisWindowRef window, 
18                                        QWidget *parent)
19   : QMainWindow(parent),
20     analysis(m),
21     subanalysis_window(window),
22     pick_align_menu(tr("Choose Alignment")),
23     view_align_menu(tr("View Alignment")),
24     zoom(0),
25     alignTB(0)
26 {
27   setupActions();
28   browser.setSequences(analysis->sequences(), analysis->colorMapper());
29   setSelectedPaths(analysis, sel_paths);
30   setAlignment(0);
31   double zoom_level = browser.zoomToSequence();
32
33   zoom = new ZoomWidget();
34   connect(zoom, SIGNAL(valueChanged(double)), 
35           &browser, SLOT(setZoom(double)));
36   zoom->setValue(zoom_level);
37   computeMatchLines();
38   setupMenus();
39   setupAlignmentMenus();
40   
41   setCentralWidget(&browser);
42
43   alignTB = new QToolBar();
44   alignTB->addWidget(zoom);
45   addToolBar(alignTB);
46   
47   ostringstream message;
48   message << "Selected " << selected_paths.size() << " paths";
49   statusBar()->showMessage(message.str().c_str(), 5000);
50   browser.updatePosition();
51 }
52
53 void MussaAlignedWindow::setupActions()
54 {
55   // more cut-n-paste from MussaWindow
56   createSubAnalysisAction = new QAction(tr("Add to Subanalysis"), this);
57   connect(createSubAnalysisAction, SIGNAL(triggered()), 
58           this, SLOT(createSubAnalysis()));
59             
60   //Save pixel map action
61   saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
62   connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
63           &browser, SLOT(promptSaveBrowserPixmap()));
64   saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
65 }
66
67 void MussaAlignedWindow::setupMenus()
68 {
69   QMenu *newMenu = menuBar()->addMenu(tr("&File"));
70   newMenu->addAction(saveBrowserPixmapAction);
71
72   newMenu = menuBar()->addMenu(tr("&Edit"));
73   newMenu->addAction(browser.getCopySelectedSequenceAsFastaAction());
74   newMenu->addAction(createSubAnalysisAction);
75   
76   // add some extra features to the context menu
77   QMenu *popupMenu = browser.getPopupMenu();
78   if (popupMenu) {
79     popupMenu->addAction(createSubAnalysisAction);
80   }  
81 }
82
83 void MussaAlignedWindow::setupAlignmentMenus()
84 {
85   pick_align_menu.clear();
86   view_align_menu.clear();
87   pick_actions.clear();
88   view_actions.clear();
89
90   for(vector<ConservedPath >::iterator pathz_i=selected_paths.begin(); 
91       pathz_i != selected_paths.end(); 
92       ++pathz_i)
93   {
94     ConservedPath::path_type normalized_path = pathz_i->normalizedIndexes();
95     ostringstream menu_text;
96     menu_text << pathz_i->window_size << ":";
97     ConservedPath::iterator element_i = normalized_path.begin();
98     menu_text << *element_i++;
99     for (;
100          element_i != normalized_path.end();
101          ++element_i)
102     {
103       menu_text << ", ";
104       menu_text << *element_i;
105     }
106     int index = pathz_i - selected_paths.begin();
107     IntAction *pick = new IntAction(QString(menu_text.str().c_str()), index, this);
108     connect(pick, SIGNAL(triggered(int)), this, SLOT(setAlignment(int)));
109     pick_actions.push_back(pick);
110     pick_align_menu.addAction(pick);
111     IntAction *view = new IntAction(QString(menu_text.str().c_str()), index, this);
112     connect(view, SIGNAL(triggered(int)), this, SLOT(toggleViewAlignment(int)));
113     view->setCheckable(true);
114     view->setChecked(true);
115     view_actions.push_back(view);
116     view_align_menu.addAction(view);
117   }
118
119   menuBar()->addMenu(&pick_align_menu);
120   menuBar()->addMenu(&view_align_menu);
121 }
122
123
124 void MussaAlignedWindow::setSelectedPaths(MussaRef m, const set<int>& sel_paths)
125 {
126   // sets are sorted
127   set<int>::iterator sel_i = sel_paths.begin();
128   list<ConservedPath>::const_iterator path_i = m->paths().refined_pathz.begin();
129   list<ConservedPath>::const_iterator path_end = m->paths().refined_pathz.end();
130   size_t path_size = m->paths().refined_pathz.size();
131   size_t pathid=0;
132
133   selected_paths.reserve(sel_paths.size());
134   view_paths.reserve(sel_paths.size());
135   while (pathid != path_size and sel_i != sel_paths.end())
136   {
137     assert (*sel_i >= 0);
138     size_t sel_pathid = (size_t)(*sel_i);
139     if (pathid == sel_pathid) {
140       selected_paths.push_back(*path_i);
141       view_paths.push_back(true);
142       ++pathid;
143       ++path_i;
144       ++sel_i;
145     } else if (pathid < sel_pathid) {
146       ++pathid;
147       ++path_i;
148     } else if (pathid > sel_pathid) {
149       ++sel_i;
150     }
151   }
152 }
153
154 // FIXME: this is a cut-n-paste from MussaWindow, perhaps they should be refactored to
155 // some shared place
156 void MussaAlignedWindow::createSubAnalysis()
157 {
158   list<SequenceLocation> result;
159   SequenceLocationModel& model = subanalysis_window->getModel();
160   browser.copySelectedTracksAsSeqLocation(result);
161   for(list<SequenceLocation>::iterator result_itor = result.begin();
162       result_itor != result.end();
163       ++result_itor)
164   {
165     model.push_back(*result_itor);
166   }
167
168   if (not subanalysis_window->isVisible()) {
169     subanalysis_window->show();
170   }
171 }
172
173 void MussaAlignedWindow::setAlignment(int alignment_index)
174 {
175   if (selected_paths.size() > 0) {
176     browser.centerOnPath(selected_paths[alignment_index].normalizedIndexes());
177   }
178 }
179
180 void MussaAlignedWindow::toggleViewAlignment(int alignment_index)
181 {
182   view_paths[alignment_index]= not view_paths[alignment_index]; 
183   // perhaps it'd be better if we could erase specific sets
184   // of matches instead of erasing them all and recomputing them all
185   // but this is easier
186   computeMatchLines();
187 }
188
189 void MussaAlignedWindow::update()
190 {
191   browser.update();
192 }
193
194 void MussaAlignedWindow::computeMatchLines()
195 {
196   browser.clear_links();
197   
198   // filter out conserved paths
199   list<ConservedPath> filtered_paths;
200   vector<ConservedPath>::iterator path_i = selected_paths.begin();
201   list<ConservedPath::path_type> result;
202   list<vector<bool> > reversed;
203
204   for(vector<ConservedPath>::size_type count = 0; 
205       count != selected_paths.size();
206       ++count, ++path_i)
207   {
208     if (view_paths[count]) 
209       filtered_paths.push_back(*path_i);
210   }
211   analysis->createLocalAlignment(filtered_paths.begin(), 
212                                  filtered_paths.end(),
213                                  result, 
214                                  reversed);
215
216   list<ConservedPath::path_type>::const_iterator result_i = result.begin();
217   list<vector<bool> >::const_iterator reversed_i = reversed.begin();
218   for(int i = 0; i != result.size(); ++i, ++result_i, ++reversed_i)
219   {
220     // make 1 base long links
221     browser.link(*result_i, *reversed_i, 1);
222   }
223 }