13 #include "qui/MussaWindow.hpp"
14 #include "mussa_exceptions.hpp"
20 MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) :
25 mussaViewTB("Path Views"),
29 closeAction(0) // initialize one of the pointers to null as a saftey flag
34 //This next setWhatsThis function prevents
35 // a segfault when using WhatsThis feature with
37 //scene->setWhatsThis(tr("Mussa in OpenGL!"));
38 setCentralWidget(&browser);
39 // well updatePosition isn't quite right as we really just need
41 connect(this, SIGNAL(changedAnnotations()), &browser, SLOT(update()));
43 mussaViewTB.addAction(toggleMotifsAction);
45 zoomLabel.setPixmap(QIcon(":/icons/viewmag.png").pixmap(16, 16));
46 zoomLabel.setToolTip(tr("Zoom"));
47 zoomLabel.setWhatsThis(tr("Zoom magnification factor"));
48 mussaViewTB.addWidget(&zoomLabel);
50 zoomBox.setToolTip(tr("Zoom"));
51 zoomBox.setWhatsThis(tr("Zoom magnification factor"));
52 zoomBox.setRange(1,10000000);
53 mussaViewTB.addWidget(&zoomBox);
54 connect(&zoomBox, SIGNAL(valueChanged(int)),
55 &browser, SLOT(setZoom(int)));
57 threshold.setRange(10,30);
58 threshold.setThreshold(20);
59 //scene->setClipPlane(20);
60 // FIXME: for when we get the paths drawn at the appropriate depth
61 //connect(&threshold, SIGNAL(thresholdChanged(int)),
62 // this, SLOT(setClipPlane(int)));
63 connect(&threshold, SIGNAL(thresholdChanged(int)),
64 this, SLOT(setSoftThreshold(int)));
65 mussaViewTB.addWidget(&threshold);
67 addToolBar(&mussaViewTB);
69 statusBar()->showMessage("Welcome to mussa", 2000);
73 void MussaWindow::setAnalysis(Mussa *new_analysis)
75 if (new_analysis != 0) {
76 // only switch mussas if we loaded without error
78 analysis = new_analysis;
83 void MussaWindow::setupActions()
85 // we really don't want to run this more than once.
86 assert (closeAction == 0);
88 // the ever popular about box
89 aboutAction = new QAction(tr("&About"), this);
90 connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
91 aboutAction->setIcon(QIcon(":/icons/info.png"));
94 closeAction = new QAction(tr("&Close"), this);
95 closeAction->setStatusTip(tr("Close this window"));
96 connect(closeAction, SIGNAL(triggered()), this, SLOT(close()));
97 closeAction->setIcon(QIcon(":/icons/exit.png"));
99 createNewAnalysisAction = new QAction(tr("Define Analysis"), this);
100 connect(createNewAnalysisAction, SIGNAL(triggered()),
101 this, SLOT(createNewAnalysis()));
102 createNewAnalysisAction->setIcon(QIcon(":/icons/filenew.png"));
104 createSubAnalysisAction = new QAction(tr("Define SubAnalysis"), this);
105 connect(createSubAnalysisAction, SIGNAL(triggered()),
106 this, SLOT(createSubAnalysis()));
108 editMotifsAction = new QAction(tr("Edit Motifs"), this);;
109 connect(editMotifsAction, SIGNAL(triggered()), this, SLOT(editMotifs()));
111 loadMotifListAction = new QAction(tr("Load Motif List"), this);
112 connect(loadMotifListAction, SIGNAL(triggered()),
113 this, SLOT(loadMotifList()));
114 loadMotifListAction->setIcon(QIcon(":/icons/fileopen.png"));
116 loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
117 connect(loadMupaAction, SIGNAL(triggered()),
118 this, SLOT(loadMupa()));
119 loadMupaAction->setIcon(QIcon(":/icons/fileopen.png"));
121 loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
122 connect(loadSavedAnalysisAction, SIGNAL(triggered()),
123 this, SLOT(loadSavedAnalysis()));
124 loadSavedAnalysisAction->setIcon(QIcon(":/icons/fileopen.png"));
126 saveMotifListAction = new QAction(tr("Save Motifs"), this);
127 connect(saveMotifListAction, SIGNAL(triggered()),
128 this, SLOT(saveMotifList()));
129 saveMotifListAction->setIcon(QIcon(":/icons/filesave.png"));
131 showMussaViewToolbarAction = new QAction(tr("Show Toolbar"), this);
132 connect(showMussaViewToolbarAction, SIGNAL(triggered()),
133 this, SLOT(showMussaToolbar()));
134 showMussaViewToolbarAction->setCheckable(true);
135 showMussaViewToolbarAction->setChecked(true);
137 toggleMotifsAction = new QAction(tr("Toggle Motifs"), this);
138 connect(toggleMotifsAction, SIGNAL(triggered()),
139 this, SLOT(toggleMotifs()));
140 toggleMotifsAction->setCheckable(true);
141 toggleMotifsAction->setIcon(QIcon(":/icons/motif_icon.png"));
142 toggleMotifsAction->setWhatsThis(tr("Toggle motif annotations on/off\n\n"
143 "You can load motif annotations via "
144 "'File->Load Motif List' menu option."));
146 //Save pixel map action
147 saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
148 connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
149 &browser, SLOT(promptSaveBrowserPixmap()));
150 saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
152 viewMussaAlignmentAction = new QAction(tr("View mussa alignment"), this);
153 connect(viewMussaAlignmentAction, SIGNAL(triggered()),
154 this, SLOT(viewMussaAlignment() ));
155 viewMussaAlignmentAction->setWhatsThis(tr("Create a zoomed in window "
156 "showing alignment of the seqcomp "
159 whatsThisAction = QWhatsThis::createAction(this);
160 whatsThisAction->setIcon(QIcon(":/icons/help.png"));
164 void MussaWindow::setupMainMenu()
166 // we need to run setupActions first
167 assert (closeAction != 0);
170 newMenu = menuBar()->addMenu(tr("&File"));
171 newMenu->addAction(createNewAnalysisAction);
172 newMenu->addAction(loadMupaAction);
173 newMenu->addAction(loadSavedAnalysisAction);
174 //newMenu->addAction(createSubAnalysisAction);
175 newMenu->addSeparator();
176 newMenu->addAction(loadMotifListAction);
177 newMenu->addAction(saveMotifListAction);
178 newMenu->addSeparator();
179 newMenu->addAction(saveBrowserPixmapAction);
180 newMenu->addSeparator();
181 newMenu->addAction(closeAction);
183 newMenu = menuBar()->addMenu(tr("&View"));
184 newMenu->addAction(editMotifsAction);
185 newMenu->addAction(viewMussaAlignmentAction);
186 newMenu->addAction(showMussaViewToolbarAction);
188 newMenu = menuBar()->addMenu(tr("&Help"));
189 newMenu->addAction(whatsThisAction);
190 newMenu->addSeparator();
191 newMenu->addAction(aboutAction);
194 void MussaWindow::about()
196 QString msg("Welcome to Multiple Species Sequence Analysis\n"
197 "(c) 2005-2006 California Institute of Technology\n"
198 "Tristan De Buysscher, Diane Trout\n");
201 msg += QDir::currentPath();
204 msg += (char *)glGetString(GL_VERSION);
206 QMessageBox::about(this, tr("About mussa"), msg);
209 void MussaWindow::createNewAnalysis()
212 if (setup_analysis_dialog.exec()) {
214 m = setup_analysis_dialog.getMussa();
217 std::cout << "New mussa exp. aborted!\n";
219 } catch(mussa_error e) {
220 QString msg(e.what());
221 QMessageBox::warning(this, tr("Create New Analysis"), msg);
225 void MussaWindow::createSubAnalysis()
230 void MussaWindow::editMotifs()
232 if (motif_editor != 0) {
233 motif_editor->hide();
236 motif_editor = new MotifEditor(analysis);
237 connect(motif_editor, SIGNAL(changedMotifs()),
238 this, SLOT(updateAnnotations()));
239 motif_editor->show();
242 void MussaWindow::loadMotifList()
244 QString caption("Load a motif list");
245 QString filter("Motif list(*.txt *.mtl)");
246 QString path = QFileDialog::getOpenFileName(this,
253 // try to load safely
255 analysis->load_motifs(path.toStdString());
256 } catch (runtime_error e) {
257 QString msg("Unable to load ");
261 QMessageBox::warning(this, "Load Motifs", msg);
263 assert (analysis != 0);
266 void MussaWindow::saveMotifList()
271 void MussaWindow::loadMupa()
273 QString caption("Load a mussa parameter file");
274 QString filter("Mussa Parameters (*.mupa)");
275 QString mupa_path = QFileDialog::getOpenFileName(this,
280 if (mupa_path.isNull())
282 // try to load safely
284 Mussa *m = new Mussa;
285 m->load_mupa_file(mupa_path.toStdString());
286 m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
288 } catch (mussa_load_error e) {
289 QString msg("Unable to load ");
293 QMessageBox::warning(this, "Load Parameter", msg);
295 assert (analysis != 0);
298 void MussaWindow::loadSavedAnalysis()
300 QString caption("Load a previously run analysis");
301 QString muway_dir = QFileDialog::getExistingDirectory(this,
303 QDir::currentPath());
305 if (muway_dir.isNull())
307 // try to safely load
309 Mussa *m = new Mussa;
310 m->load(muway_dir.toStdString());
311 // only switch mussas if we loaded without error
313 } catch (mussa_load_error e) {
314 QString msg("Unable to load ");
318 QMessageBox::warning(this, "Load Parameter", msg);
320 assert (analysis != 0);
323 void MussaWindow::setSoftThreshold(int threshold)
325 if (analysis->get_soft_thres() != threshold) {
326 analysis->set_soft_thres(threshold);
333 void MussaWindow::showMussaToolbar()
335 if (mussaViewTB.isVisible())
341 void MussaWindow::toggleMotifs()
346 void MussaWindow::NotImplementedBox()
348 QMessageBox::warning(this, QObject::tr("mussa"), QObject::tr("Not implemented yet"));
351 void MussaWindow::viewMussaAlignment()
353 const set<int>& selected_paths = browser.selectedPaths();
354 if (selected_paths.size() == 0 ) {
355 QMessageBox::warning(this,
356 QObject::tr("mussa"),
357 QObject::tr("you should probably select some paths "
360 MussaAlignedWindow *ma_win = new MussaAlignedWindow(*analysis,
362 connect(this, SIGNAL(changedAnnotations()),
363 ma_win, SLOT(update()));
364 aligned_windows.push_back(ma_win);
369 void MussaWindow::updateAnalysis()
371 cout << "analysis updated" << endl;
372 for (list<MussaAlignedWindow *>::iterator maw_i = aligned_windows.begin();
373 maw_i != aligned_windows.end();
381 const vector<Sequence>& seqs = analysis->sequences();
382 browser.setSequences(seqs, analysis->colorMapper());
385 cout << "browser zoom " << browser.zoom() << endl;
386 zoomBox.setValue(browser.zoom());
389 void MussaWindow::updateAnnotations()
391 // motifs were changed in the sequences by
392 // Mussa::update_sequences_motifs
393 emit changedAnnotations();
397 void MussaWindow::updateLinks()
399 browser.clear_links();
400 bool reversed = false;
401 const NwayPaths& nway = analysis->paths();
403 typedef list<ExtendedConservedPath> conserved_paths;
404 typedef conserved_paths::const_iterator const_conserved_paths_itor;
405 for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
406 path_itor != nway.refined_pathz.end();
409 // since we were drawing to the start of a window, and opengl lines
410 // are centered around the two connecting points our lines were slightly
411 // offset. the idea of window_offset is to adjust them to the
412 // right for forward compliment or left for reverse compliment
413 // FIXME: figure out how to unit test these computations
414 //GLfloat window_offset = (path_itor->window_size)/2.0;
416 size_t track_len = path_itor->track_indexes.size();
417 vector<int> normalized_path;
418 normalized_path.reserve(track_len);
419 vector<bool> rc_flags(false, track_len);
420 for (size_t track_i=0; track_i != track_len; ++track_i)
422 int x = path_itor->track_indexes[track_i];
423 // at some point when we modify the pathz data structure to keep
424 // track of the score we can put grab the depth here.
426 // are we reverse complimented?
431 x = -x; // make positive
433 normalized_path.push_back(x);
434 rc_flags.push_back(reversed);
436 browser.link(normalized_path, rc_flags, path_itor->window_size);