Actually copy our selected sequence to the clipboard
[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   setupActions();
24   browser.setSequences(analysis.sequences(), analysis.colorMapper());
25   setSelectedPaths(m, sel_paths);
26   setAlignment(0);
27   double zoom_level = browser.zoomToSequence();
28   zoom.setValue(zoom_level);
29   computeMatchLines();
30   setupMenus();
31   setupAlignmentMenus();
32   
33   setCentralWidget(&browser);
34
35   addToolBar(&alignTB);
36   alignTB.addWidget(&zoom);
37   
38   connect(&zoom, SIGNAL(valueChanged(double)), 
39           &browser, SLOT(setZoom(double)));
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 void MussaAlignedWindow::setupActions()
48 {
49   // create our copy action
50   copySelectedSequenceAsFastaAction = new QAction(tr("&Copy As Fasta"), this);
51   connect(copySelectedSequenceAsFastaAction, SIGNAL(triggered()), 
52           &browser, SLOT(copySelectedSequenceAsFasta()));
53
54   //Save pixel map action
55   saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
56   connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
57           &browser, SLOT(promptSaveBrowserPixmap()));
58   saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
59 }
60
61 void MussaAlignedWindow::setupMenus()
62 {
63   QMenu *newMenu = menuBar()->addMenu(tr("&File"));
64   newMenu->addAction(saveBrowserPixmapAction);
65
66   newMenu = menuBar()->addMenu(tr("&Edit"));
67   newMenu->addAction(copySelectedSequenceAsFastaAction);
68
69 }
70
71 void MussaAlignedWindow::setupAlignmentMenus()
72 {
73   pick_align_menu.clear();
74   view_align_menu.clear();
75   pick_actions.clear();
76   view_actions.clear();
77
78   for(vector<ConservedPath >::iterator pathz_i=selected_paths.begin(); 
79       pathz_i != selected_paths.end(); 
80       ++pathz_i)
81   {
82     ConservedPath::path_type normalized_path = pathz_i->normalizedIndexes();
83     ostringstream menu_text;
84     menu_text << pathz_i->window_size << ":";
85     ConservedPath::iterator element_i = normalized_path.begin();
86     menu_text << *element_i++;
87     for (;
88          element_i != normalized_path.end();
89          ++element_i)
90     {
91       menu_text << ", ";
92       menu_text << *element_i;
93     }
94     int index = pathz_i - selected_paths.begin();
95     IntAction *pick = new IntAction(QString(menu_text.str().c_str()), index, this);
96     connect(pick, SIGNAL(triggered(int)), this, SLOT(setAlignment(int)));
97     pick_actions.push_back(pick);
98     pick_align_menu.addAction(pick);
99     IntAction *view = new IntAction(QString(menu_text.str().c_str()), index, this);
100     connect(view, SIGNAL(triggered(int)), this, SLOT(toggleViewAlignment(int)));
101     view->setCheckable(true);
102     view->setChecked(true);
103     view_actions.push_back(view);
104     view_align_menu.addAction(view);
105   }
106
107   menuBar()->addMenu(&pick_align_menu);
108   menuBar()->addMenu(&view_align_menu);
109 }
110
111
112 void MussaAlignedWindow::setSelectedPaths(Mussa &m, const set<int>& sel_paths)
113 {
114   // sets are sorted
115   set<int>::iterator sel_i = sel_paths.begin();
116   list<ConservedPath>::const_iterator path_i = m.paths().refined_pathz.begin();
117   list<ConservedPath>::const_iterator path_end = m.paths().refined_pathz.end();
118   size_t path_size = m.paths().refined_pathz.size();
119   size_t pathid=0;
120
121   selected_paths.reserve(sel_paths.size());
122   view_paths.reserve(sel_paths.size());
123   while (pathid != path_size and sel_i != sel_paths.end())
124   {
125     assert (*sel_i >= 0);
126     size_t sel_pathid = (size_t)(*sel_i);
127     if (pathid == sel_pathid) {
128       selected_paths.push_back(*path_i);
129       view_paths.push_back(true);
130       ++pathid;
131       ++path_i;
132       ++sel_i;
133     } else if (pathid < sel_pathid) {
134       ++pathid;
135       ++path_i;
136     } else if (pathid > sel_pathid) {
137       ++sel_i;
138     }
139   }
140 }
141
142 void MussaAlignedWindow::setAlignment(int alignment_index)
143 {
144   if (selected_paths.size() > 0) {
145     browser.centerOnPath(selected_paths[alignment_index].normalizedIndexes());
146   }
147 }
148
149 void MussaAlignedWindow::toggleViewAlignment(int alignment_index)
150 {
151   view_paths[alignment_index]= not view_paths[alignment_index]; 
152   // perhaps it'd be better if we could erase specific sets
153   // of matches instead of erasing them all and recomputing them all
154   // but this is easier
155   computeMatchLines();
156 }
157
158 void MussaAlignedWindow::update()
159 {
160   browser.update();
161 }
162
163 void MussaAlignedWindow::computeMatchLines()
164 {
165   browser.clear_links();
166   
167   // filter out conserved paths
168   list<ConservedPath> filtered_paths;
169   vector<ConservedPath>::iterator path_i = selected_paths.begin();
170   list<ConservedPath::path_type> result;
171   list<vector<bool> > reversed;
172
173   for(vector<ConservedPath>::size_type count = 0; 
174       count != selected_paths.size();
175       ++count, ++path_i)
176   {
177     if (view_paths[count]) 
178       filtered_paths.push_back(*path_i);
179   }
180   analysis.createLocalAlignment(filtered_paths.begin(), 
181                                 filtered_paths.end(),
182                                 result, 
183                                 reversed);
184
185   list<ConservedPath::path_type>::const_iterator result_i = result.begin();
186   list<vector<bool> >::const_iterator reversed_i = reversed.begin();
187   for(int i = 0; i != result.size(); ++i, ++result_i, ++reversed_i)
188   {
189     // make 1 base long links
190     browser.link(*result_i, *reversed_i, 1);
191   }
192 }