#include "py/python.hpp"
#include "qui/MussaWindow.hpp"
#include "mussa_exceptions.hpp"
+#include "version.hpp"
#include <QAction>
#include <QApplication>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/convenience.hpp>
namespace fs = boost::filesystem;
#include <boost/bind.hpp>
using namespace std;
-MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) :
+MussaWindow::MussaWindow(MussaRef analysis_, QWidget *parent) :
QMainWindow(parent),
analysis(analysis_),
- default_dir(QDir::home().absolutePath().toStdString(), fs::native),
+ default_dir(new QDir(QDir::home().absolutePath())),
motif_editor(0),
- setup_analysis_dialog(this),
- browser(this),
- mussaViewTB("Path Views"),
- zoom(),
- threshold(),
+ setup_analysis_dialog(new MussaSetupDialog(this)),
+ subanalysis_window(new SubanalysisWindow(analysis)),
+ browser(new SequenceBrowserWidget(default_dir, this)),
+ mussaViewTB(new QToolBar("Path Views")),
+ zoom(new ZoomWidget),
+ threshold(new ThresholdWidget),
progress_dialog(0),
aboutAction(0),
closeAction(0),
// a segfault when using WhatsThis feature with
// opengl widget.
//scene->setWhatsThis(tr("Mussa in OpenGL!"));
- setCentralWidget(&browser);
+ setCentralWidget(browser);
// well updatePosition isn't quite right as we really just need
// to call update()
- connect(this, SIGNAL(changedAnnotations()), &browser, SLOT(update()));
+ connect(this, SIGNAL(changedAnnotations()), browser, SLOT(update()));
+ connect(this, SIGNAL(changedMotifs()), this, SLOT(updateAnnotations()));
- //mussaViewTB.addAction(toggleMotifsAction);
- mussaViewTB.addWidget(&zoom);
+ //mussaViewTB->addAction(toggleMotifsAction);
+ mussaViewTB->addWidget(zoom);
- connect(&zoom, SIGNAL(valueChanged(double)),
- &browser, SLOT(setZoom(double)));
+ connect(zoom, SIGNAL(valueChanged(double)),
+ browser, SLOT(setZoom(double)));
// threshold range is set in updateAnalysis
//scene->setClipPlane(20);
// FIXME: for when we get the paths drawn at the appropriate depth
- //connect(&threshold, SIGNAL(thresholdChanged(int)),
+ //connect(threshold, SIGNAL(thresholdChanged(int)),
// this, SLOT(setClipPlane(int)));
- connect(&threshold, SIGNAL(thresholdChanged(int)),
+ connect(threshold, SIGNAL(thresholdChanged(int)),
this, SLOT(setSoftThreshold(int)));
- mussaViewTB.addWidget(&threshold);
+ mussaViewTB->addWidget(threshold);
- addToolBar(&mussaViewTB);
+ addToolBar(mussaViewTB);
statusBar()->showMessage("Welcome to mussa", 2000);
- connect(analysis, SIGNAL(progress(const std::string&, int, int)),
- this, SLOT(updateProgress(const std::string&, int, int)));
+ // FIXME: we should start refactoring the connect call to updateAnalysis or something
+ if (analysis) {
+ connect(analysis.get(), SIGNAL(progress(const std::string&, int, int)),
+ this, SLOT(updateProgress(const std::string&, int, int)));
+ }
+ updateTitle();
updateAnalysis();
}
-void MussaWindow::setAnalysis(Mussa *new_analysis)
+void MussaWindow::setAnalysis(MussaRef new_analysis)
{
if (new_analysis != 0) {
// only switch mussas if we loaded without error
clear();
- delete analysis;
- analysis = new_analysis;
- setWindowTitle(analysis->get_name().c_str());
+ analysis.swap(new_analysis);
+ updateTitle();
updateAnalysis();
}
}
//Save pixel map action
saveBrowserPixmapAction = new QAction(tr("Save to image..."), this);
connect(saveBrowserPixmapAction, (SIGNAL(triggered())),
- &browser, SLOT(promptSaveBrowserPixmap()));
+ browser, SLOT(promptSaveBrowserPixmap()));
saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png"));
viewMussaAlignmentAction = new QAction(tr("View sequence alignment"), this);
newMenu = menuBar()->addMenu(tr("&Edit"));
newMenu->addAction(editMotifsAction);
- newMenu->addAction(&browser.getCopySelectedSequenceAsFastaAction());
+ newMenu->addAction(browser->getCopySelectedSequenceAsFastaAction());
newMenu->addAction(createSubAnalysisAction);
newMenu = menuBar()->addMenu(tr("&View"));
newMenu->addAction(aboutAction);
// add some extra features to the context menu
- QMenu& popupMenu = browser.getPopupMenu();
- popupMenu.addAction(viewMussaAlignmentAction);
- popupMenu.addAction(createSubAnalysisAction);
+ QMenu *popupMenu = browser->getPopupMenu();
+ if (popupMenu) {
+ popupMenu->addAction(viewMussaAlignmentAction);
+ popupMenu->addAction(createSubAnalysisAction);
+ }
}
void MussaWindow::setupAssistant()
{
-#if defined(QT_ASSISTANT_FOUND)
+#if defined(QT_QTASSISTANT_FOUND)
QStringList manualAssistantArgs;
manualAssistantArgs = QStringList();
manualAssistantArgs << "-profile" << "./doc/manual/mussagl_manual.adp";
void MussaWindow::about()
{
- QString msg("Welcome to Multiple Species Sequence Analysis\n"
- "(c) 2005-2006 California Institute of Technology\n"
- "Tristan De Buysscher, Diane Trout\n");
- msg += "\n\r";
- msg += "OpenGL: ";
- msg += (char *)glGetString(GL_VERSION);
- msg += "\n";
- QMessageBox::about(this, tr("About mussa"), msg);
+ QString msg;
+ msg += "Welcome to Multiple Species Sequence Analysis\n";
+ msg += "(c) 2005-2006 California Institute of Technology\n";
+ msg += "Diane Trout, Tristan De Buysscher, Brandon King\n";
+ msg += "Version: ";
+ msg += mussa_version;
+ msg += "\n";
+ msg += "OpenGL: ";
+ msg += (char *)glGetString(GL_VERSION);
+ msg += "\n";
+ QMessageBox::about(this, tr("About mussa"), msg);
}
void MussaWindow::clear()
{
aligned_windows.clear();
- browser.clear();
+ browser->clear();
}
void MussaWindow::createNewAnalysis()
// but this should work for the moment.
if (not isClearingAnalysisSafe()) return;
- if (setup_analysis_dialog.exec()) {
- Mussa *m = 0;
- m = setup_analysis_dialog.getMussa();
- setAnalysis(m);
+ if (setup_analysis_dialog->exec()) {
+ setAnalysis(setup_analysis_dialog->getMussa());
}
} catch(mussa_error e) {
QString msg(e.what());
void MussaWindow::createSubAnalysis()
{
list<SequenceLocation> result;
- SequenceLocationModel& model = subanalysis_window.getModel();
- browser.copySelectedTracksAsSeqLocation(result);
+ SequenceLocationModel& model = subanalysis_window->getModel();
+ browser->copySelectedTracksAsSeqLocation(result);
for(list<SequenceLocation>::iterator result_itor = result.begin();
result_itor != result.end();
++result_itor)
model.push_back(*result_itor);
}
- if (not subanalysis_window.isVisible()) {
- subanalysis_window.show();
+ if (not subanalysis_window->isVisible()) {
+ subanalysis_window->show();
}
}
std::auto_ptr<QFileDialog> dialog(new QFileDialog(this));
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->setFileMode(QFileDialog::AnyFile);
- dialog->setDirectory(QDir(default_dir.native_directory_string().c_str()));
+ dialog->setDirectory(*default_dir);
QStringList fileNames;
if (not dialog->exec()) {
if (fileNames.size() != 1) {
return;
}
-
- fs::path save_path(fileNames[0].toStdString());
+ fs::path save_path(fileNames[0].toStdString(), fs::native);
// do you want to overwrite?
if (fs::exists(save_path) and
QMessageBox::question(
return;
}
analysis->save(save_path);
- default_dir = (save_path / "..").normalize();
+ fs::path normalized_path = (save_path / "..").normalize();
+ default_dir->setPath(normalized_path.native_directory_string().c_str());
}
bool MussaWindow::isClearingAnalysisSafe()
void MussaWindow::loadMotifList()
{
- QString caption("Load a motif list");
+ QString caption("Mussa Load Motifs");
QString filter("Motif list(*.txt *.mtl)");
- QDir default_qdir(default_dir.native_directory_string().c_str());
QString path = QFileDialog::getOpenFileName(this,
caption,
- default_qdir.absolutePath(),
+ default_dir->absolutePath(),
filter);
// user hit cancel?
if (path.isNull())
try {
fs::path converted_path(path.toStdString(), fs::native);
analysis->load_motifs(converted_path);
- default_dir = converted_path.branch_path();
+ default_dir->setPath(converted_path.branch_path().native_directory_string().c_str());
+ emit changedMotifs();
} catch (runtime_error e) {
QString msg("Unable to load ");
msg += path;
msg += "\n";
msg += e.what();
- QMessageBox::warning(this, "Load Motifs", msg);
+ QMessageBox::warning(this, caption, msg);
}
- assert (analysis != 0);
}
void MussaWindow::saveMotifList()
{
- NotImplementedBox();
-}
+ QString caption("Mussa Save Motifs");
+ QString filter("Motif list(*.txt *.mtl)");
+ QString path = QFileDialog::getSaveFileName(this,
+ caption,
+ default_dir->absolutePath(),
+ filter);
+ // user hit cancel?
+ if (path.isNull())
+ return;
+ // try to load safely
+ try {
+ fs::path converted_path(path.toStdString(), fs::native);
+ if (fs::extension(converted_path).size() == 0) {
+ // no extension, so add one
+ converted_path = converted_path.string() + ".mtl";
+ }
+ analysis->save_motifs(converted_path);
+ default_dir->setPath(converted_path.branch_path().native_directory_string().c_str());
+ } catch (runtime_error e) {
+ QString msg("Unable to save ");
+ msg += path;
+ msg += "\n";
+ msg += e.what();
+ QMessageBox::warning(this, caption, msg);
+ }}
void MussaWindow::loadMupa()
{
QString caption("Load a mussa parameter file");
QString filter("Mussa Parameters (*.mupa)");
- QDir default_qdir(QDir(default_dir.native_directory_string().c_str()));
-
QString mupa_path = QFileDialog::getOpenFileName(
this,
caption,
- default_qdir.absolutePath(),
+ default_dir->absolutePath(),
filter
);
// user hit cancel?
// but this should work for the moment.
if (not isClearingAnalysisSafe()) return;
- Mussa *m = new Mussa;
+ MussaRef m(new Mussa);
fs::path converted_path(mupa_path.toStdString(), fs::native);
- connect(m, SIGNAL(progress(const std::string&, int, int)),
+ connect(m.get(), SIGNAL(progress(const std::string&, int, int)),
this, SLOT(updateProgress(const std::string&, int, int)));
m->load_mupa_file(converted_path);
m->analyze();
setAnalysis(m);
- setWindowTitle(converted_path.native_file_string().c_str());
+ updateTitle();
// grab the path ignoring the mupa file portion
- default_dir = converted_path.branch_path();
+ default_dir->setPath(converted_path.branch_path().native_directory_string().c_str());
} catch (mussa_load_error e) {
QString msg("Unable to load ");
msg += mupa_path;
void MussaWindow::loadSavedAnalysis()
{
- QDir default_qdir(QDir(default_dir.native_directory_string().c_str()));
QString caption("Load a previously run analysis");
QString muway_dir = QFileDialog::getExistingDirectory(
this,
caption,
- default_qdir.absolutePath()
+ default_dir->absolutePath()
);
// user hit cancel?
if (muway_dir.isNull())
// but this should work for the moment.
if (not isClearingAnalysisSafe()) return;
- Mussa *m = new Mussa;
+ MussaRef m(new Mussa);
fs::path converted_path(muway_dir.toStdString(), fs::native);
- connect(m, SIGNAL(progress(const std::string&, int, int)),
+ connect(m.get(), SIGNAL(progress(const std::string&, int, int)),
this, SLOT(updateProgress(const std::string&, int, int)));
m->load(converted_path);
// only switch mussas if we loaded without error
- setAnalysis(m);
- setWindowTitle(converted_path.native_file_string().c_str());
- default_dir = converted_path.branch_path();
+ if (analysis->empty()) {
+ // our current window is empty so load and replace.
+ setAnalysis(m);
+ updateTitle();
+ default_dir->setPath(converted_path.branch_path().native_directory_string().c_str());
+ } else {
+ MussaWindow *win = new MussaWindow(m);
+ updateTitle();
+ win->default_dir->setPath(converted_path.branch_path().native_directory_string().c_str());
+ win->show();
+ }
} catch (mussa_load_error e) {
QString msg("Unable to load ");
msg += muway_dir;
void MussaWindow::newMussaWindow()
{
- Mussa *a = new Mussa();
+ MussaRef a(new Mussa);
MussaWindow *win = new MussaWindow(a);
+ win->default_dir = default_dir;
win->show();
}
void MussaWindow::showMussaToolbar()
{
- if (mussaViewTB.isVisible())
- mussaViewTB.hide();
+ if (mussaViewTB->isVisible())
+ mussaViewTB->hide();
else
- mussaViewTB.show();
+ mussaViewTB->show();
}
void MussaWindow::toggleMotifs()
void MussaWindow::showManual()
{
-#if QT_QTASSISTANT_FOUND
- manualAssistant->openAssistant();
+#if defined(QT_QTASSISTANT_FOUND)
+ if (manualAssistant) {
+ manualAssistant->openAssistant();
+ } else {
+ QMessageBox::warning(this,
+ tr("Mussa Help Error"),
+ tr("QtAssistant not setup correctly"),
+ QMessageBox::Ok,
+ QMessageBox::NoButton,
+ QMessageBox::NoButton);
+ }
#else
try {
boost::python::object webopen = get_py()["webbrowser.open"];
webopen("http://woldlab.caltech.edu/~king/mussagl_manual/");
} catch( boost::python::error_already_set ) {
PyErr_Print();
+ QMessageBox::warning(this,
+ tr("Mussa Help Error"),
+ tr("Unable to launch webbrowser"),
+ QMessageBox::Ok,
+ QMessageBox::NoButton,
+ QMessageBox::NoButton);
}
#endif //QT_QTASSISTANT_FOUND
}
void MussaWindow::viewMussaAlignment()
{
- const set<int>& selected_paths = browser.selectedPaths();
+ const set<int>& selected_paths = browser->selectedPaths();
if (selected_paths.size() == 0 ) {
QMessageBox::warning(this,
QObject::tr("mussa"),
QObject::tr("you should probably select some paths "
"first"));
} else {
- boost::shared_ptr<MussaAlignedWindow> ma_win(
- new MussaAlignedWindow(*analysis, selected_paths)
+ MussaAlignedWindowRef ma_win(
+ new MussaAlignedWindow(analysis, default_dir, selected_paths, subanalysis_window)
);
aligned_windows.push_back(ma_win);
void MussaWindow::updateAnalysis()
{
- threshold.setRange(analysis->get_threshold(),analysis->get_window());
-
const Mussa::vector_sequence_type& seqs = analysis->sequences();
- browser.setSequences(seqs, analysis->colorMapper());
+ browser->setSequences(seqs, analysis->colorMapper());
+ assert(browser->sequences().size() == analysis->size());
+
+ // setRange eventually emits something that causes updateLinks to be called
+ // but it's possible for us to not have had a chance to set out sequences
+ // yet.
+ threshold->setRange(analysis->get_threshold(),analysis->get_window());
updateLinks();
- browser.zoomOut();
- zoom.setValue(browser.zoom());
+ browser->zoomOut();
+ zoom->setValue(browser->zoom());
}
void MussaWindow::updateAnnotations()
// motifs were changed in the sequences by
// Mussa::update_sequences_motifs
emit changedAnnotations();
- browser.update();
+ browser->update();
}
void MussaWindow::updateLinks()
{
- browser.clear_links();
+ if(browser->sequences().size() == 0) {
+ // we don't have any sequences load so we have no business setting links
+ return;
+ }
+
+ browser->clear_links();
bool reversed = false;
const NwayPaths& nway = analysis->paths();
normalized_path.push_back(x);
rc_flags.push_back(reversed);
}
- browser.link(normalized_path, rc_flags, path_itor->window_size);
+ browser->link(normalized_path, rc_flags, path_itor->window_size);
}
- browser.update();
+ browser->update();
}
void
}
qApp->processEvents();
}
+
+void MussaWindow::updateTitle()
+{
+ if (analysis) {
+ setWindowTitle(analysis->get_title().c_str());
+ }
+}