6f61949f4a2fe92a52d7a24819b21026725cd723
[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(Mussa& m, 
16                                        const set<int>& sel_paths, 
17                                        QWidget *parent)
18   : QMainWindow(parent),
19     analysis(m),
20     pick_align_menu(tr("Choose Alignment")),
21     view_align_menu(tr("View Alignment"))
22 {
23   browser.setSequences(analysis.sequences(), analysis.colorMapper());
24   setSelectedPaths(m, sel_paths);
25   setAlignment(0);
26   double zoom_level = browser.zoomToSequence();
27   zoom.setValue(zoom_level);
28   computeMatchLines();
29   setupMenus();
30
31   addToolBar(&alignTB);
32   alignTB.addWidget(&zoom);
33   
34   connect(&zoom, SIGNAL(valueChanged(double)), 
35           &browser, SLOT(setZoom(double)));
36  
37   setCentralWidget(&browser);
38   menuBar()->addMenu(&pick_align_menu);
39   menuBar()->addMenu(&view_align_menu);
40
41   ostringstream message;
42   message << "Selected " << selected_paths.size() << " paths";
43   statusBar()->showMessage(message.str().c_str(), 5000);
44   browser.updatePosition();
45 }
46
47
48 void MussaAlignedWindow::setSelectedPaths(Mussa &m, const set<int>& sel_paths)
49 {
50   // sets are sorted
51   set<int>::iterator sel_i = sel_paths.begin();
52   list<ExtendedConservedPath>::const_iterator path_i = m.paths().rpbegin();
53   list<ExtendedConservedPath>::const_iterator path_end = m.paths().rpend();
54   size_t path_size = m.paths().refined_pathz.size();
55   size_t pathid=0;
56
57   selected_paths.reserve(sel_paths.size());
58   view_paths.reserve(sel_paths.size());
59   while (pathid != path_size and sel_i != sel_paths.end())
60   {
61     assert (*sel_i >= 0);
62     size_t sel_pathid = (size_t)(*sel_i);
63     if (pathid == sel_pathid) {
64       selected_paths.push_back(*path_i);
65       view_paths.push_back(true);
66       ++pathid;
67       ++path_i;
68       ++sel_i;
69     } else if (pathid < sel_pathid) {
70       ++pathid;
71       ++path_i;
72     } else if (pathid > sel_pathid) {
73       ++sel_i;
74     }
75   }
76 }
77
78 void MussaAlignedWindow::setupMenus()
79 {
80   pick_align_menu.clear();
81   view_align_menu.clear();
82   pick_actions.clear();
83   view_actions.clear();
84
85   for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
86       pathz_i != selected_paths.end(); 
87       ++pathz_i)
88   {
89     ConservedPath::path_type normalized_path = pathz_i->normalizedIndexes();
90     ostringstream menu_text;
91     menu_text << pathz_i->window_size << ":";
92     ConservedPath::iterator element_i = normalized_path.begin();
93     menu_text << *element_i++;
94     for (;
95          element_i != normalized_path.end();
96          ++element_i)
97     {
98       menu_text << ", ";
99       menu_text << *element_i;
100     }
101     int index = pathz_i - selected_paths.begin();
102     IntAction *pick = new IntAction(QString(menu_text.str().c_str()), index, this);
103     connect(pick, SIGNAL(triggered(int)), this, SLOT(setAlignment(int)));
104     pick_actions.push_back(pick);
105     pick_align_menu.addAction(pick);
106     IntAction *view = new IntAction(QString(menu_text.str().c_str()), index, this);
107     connect(view, SIGNAL(triggered(int)), this, SLOT(toggleViewAlignment(size_t)));
108     view->setCheckable(true);
109     view->setChecked(true);
110     view_actions.push_back(view);
111     view_align_menu.addAction(view);
112   }
113 }
114
115 void MussaAlignedWindow::setAlignment(int alignment_index)
116 {
117   if (selected_paths.size() > 0) {
118     browser.centerOnPath(selected_paths[alignment_index].normalizedIndexes());
119   }
120 }
121
122 void MussaAlignedWindow::toggleViewAlignment(size_t alignment_index)
123 {
124   view_paths[alignment_index]= not view_paths[alignment_index]; 
125   // perhaps it'd be better if we could erase specific sets
126   // of matches instead of erasing them all and recomputing them all
127   // but this is easier
128   computeMatchLines();
129 }
130
131 void MussaAlignedWindow::update()
132 {
133   browser.update();
134 }
135
136 void MussaAlignedWindow::computeMatchLines()
137 {
138   const vector<Sequence>& raw_sequence = analysis.sequences();
139   vector<int> aligned_path;
140   size_t i2, i3;
141   int x_start, x_end;
142   int window_length, win_i;
143   int rc_1 = 0; 
144   int rc_2 = 0;
145   vector<bool> rc_list;
146   bool full_match;
147   vector<bool> matched;
148   int align_counter;
149
150   browser.clear_links();
151   align_counter = 0;
152   for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
153       pathz_i != selected_paths.end(); 
154       ++pathz_i)
155   {
156     if (view_paths[align_counter])
157     {
158       ExtendedConservedPath& a_path = *pathz_i;
159       window_length = a_path.window_size;
160       // determine which parts of the path are RC relative to first species
161       rc_list = a_path.reverseComplimented();
162       
163       // loop over each bp in the conserved region for all sequences
164       for(win_i = 0; win_i < window_length; win_i++)
165       {
166         aligned_path.clear();
167         // determine which exact base pairs match between the sequences
168         full_match = true;
169         for(i2 = 0; i2 < a_path.size()-1; i2++)
170         {
171           // assume not rc as most likely, adjust below
172           rc_1 = 0;
173           rc_2 = 0;
174           // no matter the case, any RC node needs adjustments
175           if (a_path[i2] < 0)
176             rc_1 = window_length-1;
177           if (a_path[i2+1] < 0)
178             rc_2 = window_length-1;        
179            
180           x_start = (abs(a_path[i2]-rc_1+win_i));
181           x_end =   (abs(a_path[i2+1]-rc_2+win_i));
182           
183           // RC case handling
184           // ugh, and xor...only want rc coloring if just one of the nodes is rc
185           // if both nodes are rc, then they are 'normal' relative to each other
186           if ( ( rc_list[i2] || rc_list[i2+1] ) &&
187               !(rc_list[i2] && rc_list[i2+1] ) )
188           { //the hideous rc matching logic - not complex, but annoying
189             if ( !( ( (raw_sequence[i2][x_start] == 'A') &&
190                     (raw_sequence[i2+1][x_end] == 'T') ) ||
191                   ( (raw_sequence[i2][x_start] == 'T') &&
192                     (raw_sequence[i2+1][x_end] == 'A') ) ||
193                   ( (raw_sequence[i2][x_start] == 'G') &&
194                     (raw_sequence[i2+1][x_end] == 'C') ) ||
195                   ( (raw_sequence[i2][x_start] == 'C') &&
196                     (raw_sequence[i2+1][x_end] == 'G') ) ) )
197               full_match = false;
198           }
199           else
200           {
201             if (!( (raw_sequence[i2][x_start] == raw_sequence[i2+1][x_end]) &&
202                   (raw_sequence[i2][x_start] != 'N') &&
203                   (raw_sequence[i2+1][x_end] != 'N') ) )
204               full_match = false;
205           }
206         }
207         
208         // draw for matches stretching across all sequences
209         if (full_match)
210         {
211           // now can draw the line for each bp in this window that matches
212           // grrr, need to ask if anyone cares if I switch the seq 
213           // top-bot order...
214           i3 = 0;
215           //y_loc = y_min + 5;
216           for(i2 = 0; i2 < a_path.size()-1; i2++)
217           {
218             // assume not rc as most likely, adjust below
219             rc_1 = 0;
220             rc_2 = 0;
221             // no matter the case, any RC node needs adjustments
222             if (a_path[i2] < 0)
223             {
224               rc_1 = window_length;        
225             }
226             if (a_path[i2] < 0)
227             {
228               rc_2 = window_length;        
229             }
230             
231             // maybe shouldn't recalc these, but store values from first loop
232             x_start = (abs((int) (a_path[i2]-rc_1+win_i)));
233             x_end =   (abs((int) (a_path[i2+1]-rc_2+win_i)));
234             aligned_path.push_back(x_start);
235             // if we're on the last time through the loop, save x_end too
236             if (i2 == a_path.size()-2) {
237               aligned_path.push_back(x_end);
238             }
239           }
240         }
241         if (aligned_path.size() > 0) {
242           browser.link(aligned_path, rc_list,1);
243         }
244       }
245     }
246     align_counter++;
247   }
248 }
249