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"),
33 createNewAnalysisAction(0),
34 createSubAnalysisAction(0),
36 loadMotifListAction(0),
38 loadSavedAnalysisAction(0),
39 newMussaWindowAction(0),
40 saveMotifListAction(0),
41 showMussaViewToolbarAction(0),
42 toggleMotifsAction(0),
43 saveBrowserPixmapAction(0),
45 viewMussaAlignmentAction(0)
50 //This next setWhatsThis function prevents
51 // a segfault when using WhatsThis feature with
53 //scene->setWhatsThis(tr("Mussa in OpenGL!"));
54 setCentralWidget(&browser);
55 // well updatePosition isn't quite right as we really just need
57 connect(this, SIGNAL(changedAnnotations()), &browser, SLOT(update()));
59 mussaViewTB.addAction(toggleMotifsAction);
60 mussaViewTB.addWidget(&zoom);
62 connect(&zoom, SIGNAL(valueChanged(double)),
63 &browser, SLOT(setZoom(double)));
65 // threshold range is set in updateAnalysis
67 //scene->setClipPlane(20);
68 // FIXME: for when we get the paths drawn at the appropriate depth
69 //connect(&threshold, SIGNAL(thresholdChanged(int)),
70 // this, SLOT(setClipPlane(int)));
71 connect(&threshold, SIGNAL(thresholdChanged(int)),
72 this, SLOT(setSoftThreshold(int)));
73 mussaViewTB.addWidget(&threshold);
75 addToolBar(&mussaViewTB);
77 statusBar()->showMessage("Welcome to mussa", 2000);
81 MussaWindow::~MussaWindow()
83 if (analysis != 0) delete analysis;
84 aligned_windows.clear();
85 if (motif_editor != 0) delete motif_editor;
87 if (aboutAction != 0) delete aboutAction;
88 if (closeAction != 0) delete closeAction;
89 if (createNewAnalysisAction != 0) delete createNewAnalysisAction;
90 if (createSubAnalysisAction != 0) delete createSubAnalysisAction;
91 if (editMotifsAction != 0) delete editMotifsAction;
92 if (loadMotifListAction != 0) delete loadMotifListAction;
93 if (loadMupaAction != 0) delete loadMupaAction;
94 if (loadSavedAnalysisAction != 0) delete loadSavedAnalysisAction;
95 if (newMussaWindowAction != 0) delete newMussaWindowAction;
96 if (saveMotifListAction != 0) delete saveMotifListAction;
97 if (showMussaViewToolbarAction != 0) delete showMussaViewToolbarAction;
98 if (toggleMotifsAction != 0) delete toggleMotifsAction;
99 if (saveBrowserPixmapAction != 0) delete saveBrowserPixmapAction;
100 if (whatsThisAction != 0) delete whatsThisAction;
101 if (viewMussaAlignmentAction != 0) delete viewMussaAlignmentAction;
104 void MussaWindow::setAnalysis(Mussa *new_analysis)
106 if (new_analysis != 0) {
107 // only switch mussas if we loaded without error
109 analysis = new_analysis;
110 setWindowTitle(analysis->get_name().c_str());
115 void MussaWindow::setupActions()
117 // we really don't want to run this more than once.
118 assert (closeAction == 0);
120 // the ever popular about box
121 aboutAction = new QAction(tr("&About"), this);
122 connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
123 aboutAction->setIcon(QIcon(":/icons/info.png"));
126 closeAction = new QAction(tr("&Close"), this);
127 closeAction->setStatusTip(tr("Close this window"));
128 connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
129 closeAction->setIcon(QIcon(":/icons/exit.png"));
131 createNewAnalysisAction = new QAction(tr("Define Analysis"), this);
132 connect(createNewAnalysisAction, SIGNAL(triggered()),
133 this, SLOT(createNewAnalysis()));
134 createNewAnalysisAction->setIcon(QIcon(":/icons/filenew.png"));
136 createSubAnalysisAction = new QAction(tr("Define SubAnalysis"), this);
137 connect(createSubAnalysisAction, SIGNAL(triggered()),
138 this, SLOT(createSubAnalysis()));
140 editMotifsAction = new QAction(tr("Edit Motifs"), this);;
141 connect(editMotifsAction, SIGNAL(triggered()), this, SLOT(editMotifs()));
143 loadMotifListAction = new QAction(tr("Load Motif List"), this);
144 connect(loadMotifListAction, SIGNAL(triggered()),
145 this, SLOT(loadMotifList()));
146 loadMotifListAction->setIcon(QIcon(":/icons/fileopen.png"));
148 loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
149 connect(loadMupaAction, SIGNAL(triggered()),
150 this, SLOT(loadMupa()));
151 loadMupaAction->setIcon(QIcon(":/icons/fileopen.png"));
153 loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
154 connect(loadSavedAnalysisAction, SIGNAL(triggered()),
155 this, SLOT(loadSavedAnalysis()));
156 loadSavedAnalysisAction->setIcon(QIcon(":/icons/fileopen.png"));
158 newMussaWindowAction = new QAction(tr("&New Mussa Window"), this);
159 newMussaWindowAction->setStatusTip("open another mussa window to allow comparing results");
160 connect(newMussaWindowAction, SIGNAL(triggered()),
161 this, SLOT(newMussaWindow()));
162 newMussaWindowAction->setIcon(QIcon(":/icons/window_new.png"));
164 saveMotifListAction = new QAction(tr("Save Motifs"), this);
165 connect(saveMotifListAction, SIGNAL(triggered()),
166 this, SLOT(saveMotifList()));
167 saveMotifListAction->setIcon(QIcon(":/icons/filesave.png"));
169 showMussaViewToolbarAction = new QAction(tr("Show Toolbar"), this);
170 connect(showMussaViewToolbarAction, SIGNAL(triggered()),
171 this, SLOT(showMussaToolbar()));
172 showMussaViewToolbarAction->setCheckable(true);
173 showMussaViewToolbarAction->setChecked(true);
175 toggleMotifsAction = new QAction(tr("Toggle Motifs"), this);
176 connect(toggleMotifsAction, SIGNAL(triggered()),
177 this, SLOT(toggleMotifs()));
178 toggleMotifsAction->setCheckable(true);
179 toggleMotifsAction->setIcon(QIcon(":/icons/motif_icon.png"));
180 toggleMotifsAction->setWhatsThis(tr("Toggle motif annotations on/off\n\n"
181 "You can load motif annotations via "
182 "'File->Load Motif List' menu option."));
184 //Save pixel map action
185 saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
186 connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
187 &browser, SLOT(promptSaveBrowserPixmap()));
188 saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
190 viewMussaAlignmentAction = new QAction(tr("View mussa alignment"), this);
191 connect(viewMussaAlignmentAction, SIGNAL(triggered()),
192 this, SLOT(viewMussaAlignment() ));
193 viewMussaAlignmentAction->setWhatsThis(tr("Create a zoomed in window "
194 "showing alignment of the seqcomp "
197 whatsThisAction = QWhatsThis::createAction(this);
198 whatsThisAction->setIcon(QIcon(":/icons/help.png"));
202 void MussaWindow::setupMainMenu()
204 // we need to run setupActions first
205 assert (closeAction != 0);
207 QMenu *newMenu = menuBar()->addMenu(tr("&File"));
209 newMenu->addAction(newMussaWindowAction);
210 newMenu->addAction(createNewAnalysisAction);
211 newMenu->addAction(loadMupaAction);
212 newMenu->addAction(loadSavedAnalysisAction);
213 //newMenu->addAction(createSubAnalysisAction);
214 newMenu->addSeparator();
215 newMenu->addAction(loadMotifListAction);
216 newMenu->addAction(saveMotifListAction);
217 newMenu->addSeparator();
218 newMenu->addAction(saveBrowserPixmapAction);
219 newMenu->addSeparator();
220 newMenu->addAction(closeAction);
222 newMenu = menuBar()->addMenu(tr("&View"));
223 newMenu->addAction(editMotifsAction);
224 newMenu->addAction(viewMussaAlignmentAction);
225 newMenu->addAction(showMussaViewToolbarAction);
227 newMenu = menuBar()->addMenu(tr("&Help"));
228 newMenu->addAction(whatsThisAction);
229 newMenu->addSeparator();
230 newMenu->addAction(aboutAction);
233 void MussaWindow::about()
235 QString msg("Welcome to Multiple Species Sequence Analysis\n"
236 "(c) 2005-2006 California Institute of Technology\n"
237 "Tristan De Buysscher, Diane Trout\n");
240 msg += QDir::currentPath();
243 msg += (char *)glGetString(GL_VERSION);
245 QMessageBox::about(this, tr("About mussa"), msg);
248 void MussaWindow::createNewAnalysis()
251 if (setup_analysis_dialog.exec()) {
253 m = setup_analysis_dialog.getMussa();
256 std::cout << "New mussa exp. aborted!\n";
258 } catch(mussa_error e) {
259 QString msg(e.what());
260 QMessageBox::warning(this, tr("Create New Analysis"), msg);
264 void MussaWindow::createSubAnalysis()
269 void MussaWindow::editMotifs()
271 if (motif_editor != 0) {
272 motif_editor->hide();
275 motif_editor = new MotifEditor(analysis);
276 connect(motif_editor, SIGNAL(changedMotifs()),
277 this, SLOT(updateAnnotations()));
278 motif_editor->show();
281 void MussaWindow::loadMotifList()
283 QString caption("Load a motif list");
284 QString filter("Motif list(*.txt *.mtl)");
285 QString path = QFileDialog::getOpenFileName(this,
292 // try to load safely
294 fs::path converted_path(path.toStdString(), fs::native);
295 analysis->load_motifs(converted_path);
296 } catch (runtime_error e) {
297 QString msg("Unable to load ");
301 QMessageBox::warning(this, "Load Motifs", msg);
303 assert (analysis != 0);
306 void MussaWindow::saveMotifList()
311 void MussaWindow::loadMupa()
313 QString caption("Load a mussa parameter file");
314 QString filter("Mussa Parameters (*.mupa)");
315 QString mupa_path = QFileDialog::getOpenFileName(this,
320 if (mupa_path.isNull())
322 // try to load safely
324 Mussa *m = new Mussa;
325 fs::path converted_path(mupa_path.toStdString(), fs::native);
326 m->load_mupa_file(converted_path);
327 m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
329 setWindowTitle(converted_path.native_file_string().c_str());
330 } catch (mussa_load_error e) {
331 QString msg("Unable to load ");
335 QMessageBox::warning(this, "Load Parameter", msg);
337 assert (analysis != 0);
340 void MussaWindow::loadSavedAnalysis()
342 QString caption("Load a previously run analysis");
343 QString muway_dir = QFileDialog::getExistingDirectory(this,
345 QDir::currentPath());
347 if (muway_dir.isNull())
349 // try to safely load
351 Mussa *m = new Mussa;
352 fs::path converted_path(muway_dir.toStdString(), fs::native);
353 m->load(converted_path);
354 // only switch mussas if we loaded without error
356 setWindowTitle(converted_path.native_file_string().c_str());
357 } catch (mussa_load_error e) {
358 QString msg("Unable to load ");
362 QMessageBox::warning(this, "Load Parameter", msg);
364 assert (analysis != 0);
367 void MussaWindow::newMussaWindow()
369 Mussa *a = new Mussa();
370 MussaWindow *win = new MussaWindow(a);
374 void MussaWindow::setSoftThreshold(int threshold)
376 if (analysis->get_soft_thres() != threshold) {
377 analysis->set_soft_thres(threshold);
384 void MussaWindow::showMussaToolbar()
386 if (mussaViewTB.isVisible())
392 void MussaWindow::toggleMotifs()
397 void MussaWindow::NotImplementedBox()
399 QMessageBox::warning(this, QObject::tr("mussa"), QObject::tr("Not implemented yet"));
402 void MussaWindow::viewMussaAlignment()
404 const set<int>& selected_paths = browser.selectedPaths();
405 if (selected_paths.size() == 0 ) {
406 QMessageBox::warning(this,
407 QObject::tr("mussa"),
408 QObject::tr("you should probably select some paths "
411 MussaAlignedWindow *ma_win = new MussaAlignedWindow(*analysis,
413 connect(this, SIGNAL(changedAnnotations()),
414 ma_win, SLOT(update()));
415 aligned_windows.push_back(ma_win);
420 void MussaWindow::updateAnalysis()
422 threshold.setRange(analysis->get_threshold(),analysis->get_window());
423 for (list<MussaAlignedWindow *>::iterator maw_i = aligned_windows.begin();
424 maw_i != aligned_windows.end();
432 const vector<Sequence>& seqs = analysis->sequences();
433 browser.setSequences(seqs, analysis->colorMapper());
436 zoom.setValue(browser.zoom());
439 void MussaWindow::updateAnnotations()
441 // motifs were changed in the sequences by
442 // Mussa::update_sequences_motifs
443 emit changedAnnotations();
447 void MussaWindow::updateLinks()
449 browser.clear_links();
450 bool reversed = false;
451 const NwayPaths& nway = analysis->paths();
453 typedef list<ConservedPath> conserved_paths;
454 typedef conserved_paths::const_iterator const_conserved_paths_itor;
455 for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
456 path_itor != nway.refined_pathz.end();
459 // since we were drawing to the start of a window, and opengl lines
460 // are centered around the two connecting points our lines were slightly
461 // offset. the idea of window_offset is to adjust them to the
462 // right for forward compliment or left for reverse compliment
463 // FIXME: figure out how to unit test these computations
464 //GLfloat window_offset = (path_itor->window_size)/2.0;
466 size_t track_len = path_itor->track_indexes.size();
467 vector<int> normalized_path;
468 normalized_path.reserve(track_len);
469 vector<bool> rc_flags(false, track_len);
470 for (size_t track_i=0; track_i != track_len; ++track_i)
472 int x = path_itor->track_indexes[track_i];
473 // at some point when we modify the pathz data structure to keep
474 // track of the score we can put grab the depth here.
476 // are we reverse complimented?
484 normalized_path.push_back(x);
485 rc_flags.push_back(reversed);
487 browser.link(normalized_path, rc_flags, path_itor->window_size);