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