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