13 #include "qui/MussaWindow.hpp"
14 #include "mussa_exceptions.hpp"
18 #include <boost/filesystem/path.hpp>
19 namespace fs = boost::filesystem;
23 MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) :
28 mussaViewTB("Path Views"),
31 closeAction(0) // initialize one of the pointers to null as a saftey flag
36 //This next setWhatsThis function prevents
37 // a segfault when using WhatsThis feature with
39 //scene->setWhatsThis(tr("Mussa in OpenGL!"));
40 setCentralWidget(&browser);
41 // well updatePosition isn't quite right as we really just need
43 connect(this, SIGNAL(changedAnnotations()), &browser, SLOT(update()));
45 mussaViewTB.addAction(toggleMotifsAction);
46 mussaViewTB.addWidget(&zoom);
48 connect(&zoom, SIGNAL(valueChanged(double)),
49 &browser, SLOT(setZoom(double)));
51 // threshold range is set in updateAnalysis
53 //scene->setClipPlane(20);
54 // FIXME: for when we get the paths drawn at the appropriate depth
55 //connect(&threshold, SIGNAL(thresholdChanged(int)),
56 // this, SLOT(setClipPlane(int)));
57 connect(&threshold, SIGNAL(thresholdChanged(int)),
58 this, SLOT(setSoftThreshold(int)));
59 mussaViewTB.addWidget(&threshold);
61 addToolBar(&mussaViewTB);
63 statusBar()->showMessage("Welcome to mussa", 2000);
67 MussaWindow::~MussaWindow()
69 if (analysis != 0) delete analysis;
70 aligned_windows.clear();
71 if (motif_editor != 0) delete motif_editor;
73 if (aboutAction != 0) delete aboutAction;
74 if (closeAction != 0) delete closeAction;
75 if (createNewAnalysisAction != 0) delete createNewAnalysisAction;
76 if (createSubAnalysisAction != 0) delete createSubAnalysisAction;
77 if (editMotifsAction != 0) delete editMotifsAction;
78 if (loadMotifListAction != 0) delete loadMotifListAction;
79 if (loadMupaAction != 0) delete loadMupaAction;
80 if (loadSavedAnalysisAction != 0) delete loadSavedAnalysisAction;
81 if (newMussaWindowAction != 0) delete newMussaWindowAction;
82 if (saveMotifListAction != 0) delete saveMotifListAction;
83 if (showMussaViewToolbarAction != 0) delete showMussaViewToolbarAction;
84 if (toggleMotifsAction != 0) delete toggleMotifsAction;
85 if (saveBrowserPixmapAction != 0) delete saveBrowserPixmapAction;
88 void MussaWindow::setAnalysis(Mussa *new_analysis)
90 if (new_analysis != 0) {
91 // only switch mussas if we loaded without error
93 analysis = new_analysis;
94 setWindowTitle(analysis->get_name().c_str());
99 void MussaWindow::setupActions()
101 // we really don't want to run this more than once.
102 assert (closeAction == 0);
104 // the ever popular about box
105 aboutAction = new QAction(tr("&About"), this);
106 connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
107 aboutAction->setIcon(QIcon(":/icons/info.png"));
110 closeAction = new QAction(tr("&Close"), this);
111 closeAction->setStatusTip(tr("Close this window"));
112 connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
113 closeAction->setIcon(QIcon(":/icons/exit.png"));
115 createNewAnalysisAction = new QAction(tr("Define Analysis"), this);
116 connect(createNewAnalysisAction, SIGNAL(triggered()),
117 this, SLOT(createNewAnalysis()));
118 createNewAnalysisAction->setIcon(QIcon(":/icons/filenew.png"));
120 createSubAnalysisAction = new QAction(tr("Define SubAnalysis"), this);
121 connect(createSubAnalysisAction, SIGNAL(triggered()),
122 this, SLOT(createSubAnalysis()));
124 editMotifsAction = new QAction(tr("Edit Motifs"), this);;
125 connect(editMotifsAction, SIGNAL(triggered()), this, SLOT(editMotifs()));
127 loadMotifListAction = new QAction(tr("Load Motif List"), this);
128 connect(loadMotifListAction, SIGNAL(triggered()),
129 this, SLOT(loadMotifList()));
130 loadMotifListAction->setIcon(QIcon(":/icons/fileopen.png"));
132 loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
133 connect(loadMupaAction, SIGNAL(triggered()),
134 this, SLOT(loadMupa()));
135 loadMupaAction->setIcon(QIcon(":/icons/fileopen.png"));
137 loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
138 connect(loadSavedAnalysisAction, SIGNAL(triggered()),
139 this, SLOT(loadSavedAnalysis()));
140 loadSavedAnalysisAction->setIcon(QIcon(":/icons/fileopen.png"));
142 newMussaWindowAction = new QAction(tr("&New Mussa Window"), this);
143 newMussaWindowAction->setStatusTip("open another mussa window to allow comparing results");
144 connect(newMussaWindowAction, SIGNAL(triggered()),
145 this, SLOT(newMussaWindow()));
146 newMussaWindowAction->setIcon(QIcon(":/icons/window_new.png"));
148 saveMotifListAction = new QAction(tr("Save Motifs"), this);
149 connect(saveMotifListAction, SIGNAL(triggered()),
150 this, SLOT(saveMotifList()));
151 saveMotifListAction->setIcon(QIcon(":/icons/filesave.png"));
153 showMussaViewToolbarAction = new QAction(tr("Show Toolbar"), this);
154 connect(showMussaViewToolbarAction, SIGNAL(triggered()),
155 this, SLOT(showMussaToolbar()));
156 showMussaViewToolbarAction->setCheckable(true);
157 showMussaViewToolbarAction->setChecked(true);
159 toggleMotifsAction = new QAction(tr("Toggle Motifs"), this);
160 connect(toggleMotifsAction, SIGNAL(triggered()),
161 this, SLOT(toggleMotifs()));
162 toggleMotifsAction->setCheckable(true);
163 toggleMotifsAction->setIcon(QIcon(":/icons/motif_icon.png"));
164 toggleMotifsAction->setWhatsThis(tr("Toggle motif annotations on/off\n\n"
165 "You can load motif annotations via "
166 "'File->Load Motif List' menu option."));
168 //Save pixel map action
169 saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
170 connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
171 &browser, SLOT(promptSaveBrowserPixmap()));
172 saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
174 viewMussaAlignmentAction = new QAction(tr("View mussa alignment"), this);
175 connect(viewMussaAlignmentAction, SIGNAL(triggered()),
176 this, SLOT(viewMussaAlignment() ));
177 viewMussaAlignmentAction->setWhatsThis(tr("Create a zoomed in window "
178 "showing alignment of the seqcomp "
181 whatsThisAction = QWhatsThis::createAction(this);
182 whatsThisAction->setIcon(QIcon(":/icons/help.png"));
186 void MussaWindow::setupMainMenu()
188 // we need to run setupActions first
189 assert (closeAction != 0);
192 newMenu = menuBar()->addMenu(tr("&File"));
193 newMenu->addAction(newMussaWindowAction);
194 newMenu->addAction(createNewAnalysisAction);
195 newMenu->addAction(loadMupaAction);
196 newMenu->addAction(loadSavedAnalysisAction);
197 //newMenu->addAction(createSubAnalysisAction);
198 newMenu->addSeparator();
199 newMenu->addAction(loadMotifListAction);
200 newMenu->addAction(saveMotifListAction);
201 newMenu->addSeparator();
202 newMenu->addAction(saveBrowserPixmapAction);
203 newMenu->addSeparator();
204 newMenu->addAction(closeAction);
206 newMenu = menuBar()->addMenu(tr("&View"));
207 newMenu->addAction(editMotifsAction);
208 newMenu->addAction(viewMussaAlignmentAction);
209 newMenu->addAction(showMussaViewToolbarAction);
211 newMenu = menuBar()->addMenu(tr("&Help"));
212 newMenu->addAction(whatsThisAction);
213 newMenu->addSeparator();
214 newMenu->addAction(aboutAction);
217 void MussaWindow::about()
219 QString msg("Welcome to Multiple Species Sequence Analysis\n"
220 "(c) 2005-2006 California Institute of Technology\n"
221 "Tristan De Buysscher, Diane Trout\n");
224 msg += QDir::currentPath();
227 msg += (char *)glGetString(GL_VERSION);
229 QMessageBox::about(this, tr("About mussa"), msg);
232 void MussaWindow::createNewAnalysis()
235 if (setup_analysis_dialog.exec()) {
237 m = setup_analysis_dialog.getMussa();
240 std::cout << "New mussa exp. aborted!\n";
242 } catch(mussa_error e) {
243 QString msg(e.what());
244 QMessageBox::warning(this, tr("Create New Analysis"), msg);
248 void MussaWindow::createSubAnalysis()
253 void MussaWindow::editMotifs()
255 if (motif_editor != 0) {
256 motif_editor->hide();
259 motif_editor = new MotifEditor(analysis);
260 connect(motif_editor, SIGNAL(changedMotifs()),
261 this, SLOT(updateAnnotations()));
262 motif_editor->show();
265 void MussaWindow::loadMotifList()
267 QString caption("Load a motif list");
268 QString filter("Motif list(*.txt *.mtl)");
269 QString path = QFileDialog::getOpenFileName(this,
276 // try to load safely
278 fs::path converted_path(path.toStdString(), fs::native);
279 analysis->load_motifs(converted_path);
280 } catch (runtime_error e) {
281 QString msg("Unable to load ");
285 QMessageBox::warning(this, "Load Motifs", msg);
287 assert (analysis != 0);
290 void MussaWindow::saveMotifList()
295 void MussaWindow::loadMupa()
297 QString caption("Load a mussa parameter file");
298 QString filter("Mussa Parameters (*.mupa)");
299 QString mupa_path = QFileDialog::getOpenFileName(this,
304 if (mupa_path.isNull())
306 // try to load safely
308 Mussa *m = new Mussa;
309 fs::path converted_path(mupa_path.toStdString(), fs::native);
310 m->load_mupa_file(converted_path);
311 m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
313 setWindowTitle(converted_path.native_file_string().c_str());
314 } catch (mussa_load_error e) {
315 QString msg("Unable to load ");
319 QMessageBox::warning(this, "Load Parameter", msg);
321 assert (analysis != 0);
324 void MussaWindow::loadSavedAnalysis()
326 QString caption("Load a previously run analysis");
327 QString muway_dir = QFileDialog::getExistingDirectory(this,
329 QDir::currentPath());
331 if (muway_dir.isNull())
333 // try to safely load
335 Mussa *m = new Mussa;
336 fs::path converted_path(muway_dir.toStdString(), fs::native);
337 m->load(converted_path);
338 // only switch mussas if we loaded without error
340 setWindowTitle(converted_path.native_file_string().c_str());
341 } catch (mussa_load_error e) {
342 QString msg("Unable to load ");
346 QMessageBox::warning(this, "Load Parameter", msg);
348 assert (analysis != 0);
351 void MussaWindow::newMussaWindow()
353 Mussa *a = new Mussa();
354 MussaWindow *win = new MussaWindow(a);
358 void MussaWindow::setSoftThreshold(int threshold)
360 if (analysis->get_soft_thres() != threshold) {
361 analysis->set_soft_thres(threshold);
368 void MussaWindow::showMussaToolbar()
370 if (mussaViewTB.isVisible())
376 void MussaWindow::toggleMotifs()
381 void MussaWindow::NotImplementedBox()
383 QMessageBox::warning(this, QObject::tr("mussa"), QObject::tr("Not implemented yet"));
386 void MussaWindow::viewMussaAlignment()
388 const set<int>& selected_paths = browser.selectedPaths();
389 if (selected_paths.size() == 0 ) {
390 QMessageBox::warning(this,
391 QObject::tr("mussa"),
392 QObject::tr("you should probably select some paths "
395 MussaAlignedWindow *ma_win = new MussaAlignedWindow(*analysis,
397 connect(this, SIGNAL(changedAnnotations()),
398 ma_win, SLOT(update()));
399 aligned_windows.push_back(ma_win);
404 void MussaWindow::updateAnalysis()
406 threshold.setRange(analysis->get_threshold(),analysis->get_window());
407 for (list<MussaAlignedWindow *>::iterator maw_i = aligned_windows.begin();
408 maw_i != aligned_windows.end();
416 const vector<Sequence>& seqs = analysis->sequences();
417 browser.setSequences(seqs, analysis->colorMapper());
420 zoom.setValue(browser.zoom());
423 void MussaWindow::updateAnnotations()
425 // motifs were changed in the sequences by
426 // Mussa::update_sequences_motifs
427 emit changedAnnotations();
431 void MussaWindow::updateLinks()
433 browser.clear_links();
434 bool reversed = false;
435 const NwayPaths& nway = analysis->paths();
437 typedef list<ConservedPath> conserved_paths;
438 typedef conserved_paths::const_iterator const_conserved_paths_itor;
439 for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
440 path_itor != nway.refined_pathz.end();
443 // since we were drawing to the start of a window, and opengl lines
444 // are centered around the two connecting points our lines were slightly
445 // offset. the idea of window_offset is to adjust them to the
446 // right for forward compliment or left for reverse compliment
447 // FIXME: figure out how to unit test these computations
448 //GLfloat window_offset = (path_itor->window_size)/2.0;
450 size_t track_len = path_itor->track_indexes.size();
451 vector<int> normalized_path;
452 normalized_path.reserve(track_len);
453 vector<bool> rc_flags(false, track_len);
454 for (size_t track_i=0; track_i != track_len; ++track_i)
456 int x = path_itor->track_indexes[track_i];
457 // at some point when we modify the pathz data structure to keep
458 // track of the score we can put grab the depth here.
460 // are we reverse complimented?
468 normalized_path.push_back(x);
469 rc_flags.push_back(reversed);
471 browser.link(normalized_path, rc_flags, path_itor->window_size);