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