X-Git-Url: http://woldlab.caltech.edu/gitweb/?a=blobdiff_plain;f=qui%2FMussaWindow.cpp;h=75da849d591416a25371c980e9454b8c46e737af;hb=15e1618344491d9860923656fc16be15532223a6;hp=72829c9aa4ef43329cd09e6b84626987e250bff1;hpb=221f92e7044d20031b5704fa3a57a83af2a5b3b4;p=mussa.git diff --git a/qui/MussaWindow.cpp b/qui/MussaWindow.cpp index 72829c9..75da849 100644 --- a/qui/MussaWindow.cpp +++ b/qui/MussaWindow.cpp @@ -1,4 +1,3 @@ -#include "py/python.hpp" #include "qui/MussaWindow.hpp" #include "mussa_exceptions.hpp" #include "version.hpp" @@ -7,16 +6,21 @@ #include #include #include +#include #include #include #include #include +#include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -31,17 +35,23 @@ namespace fs = boost::filesystem; using namespace std; +static void init_resources() { + static bool resources_loaded = false; + if (not resources_loaded) { + Q_INIT_RESOURCE(icons); + resources_loaded = true; + } +} + MussaWindow::MussaWindow(MussaRef analysis_, QWidget *parent) : QMainWindow(parent), analysis(analysis_), - default_dir(new QDir(QDir::home().absolutePath())), motif_editor(0), - 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), + setup_analysis_dialog(0), + browser(0), + mussaViewTB(0), + zoom(0), + threshold(0), progress_dialog(0), aboutAction(0), closeAction(0), @@ -59,34 +69,35 @@ MussaWindow::MussaWindow(MussaRef analysis_, QWidget *parent) : saveBrowserPixmapAction(0), whatsThisAction(0), viewMussaAlignmentAction(0), - manualAssistant(0) + assistantProcess(0) { + init_resources(); + + default_dir.reset(new QDir(QDir::home().absolutePath())); + + setupWidgets(); setupActions(); - setupMainMenu(); setupAssistant(); + setupMainMenu(); + + setWindowIcon(QIcon(":/icons/mussa.png")); - //This next setWhatsThis function prevents - // a segfault when using WhatsThis feature with - // opengl widget. - //scene->setWhatsThis(tr("Mussa in OpenGL!")); 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(changedMotifs()), this, SLOT(updateAnnotations())); - - //mussaViewTB->addAction(toggleMotifsAction); - mussaViewTB->addWidget(zoom); - + connect(browser, SIGNAL(basepairsCopied(size_t)), + this, SLOT(showBasePairsCopied(size_t))); connect(zoom, SIGNAL(valueChanged(double)), browser, SLOT(setZoom(double))); + mussaViewTB->addWidget(zoom); - // 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)), - // this, SLOT(setClipPlane(int))); + // Mouse Wheel triggered zooming + connect(browser, SIGNAL(mouseWheelZoom(double)), + zoom, SLOT(setValue(double))); + + // threshold range is set in updateAnalysis connect(threshold, SIGNAL(thresholdChanged(int)), this, SLOT(setSoftThreshold(int))); mussaViewTB->addWidget(threshold); @@ -94,10 +105,13 @@ MussaWindow::MussaWindow(MussaRef analysis_, QWidget *parent) : addToolBar(mussaViewTB); statusBar()->showMessage("Welcome to mussa", 2000); + // 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))); + connect(analysis.get(), SIGNAL(progress(const QString&, int, int)), + this, SLOT(updateProgress(const QString&, int, int))); + connect(analysis.get(), SIGNAL(isModified(bool)), + this, SLOT(updateAnalysisModified(bool))); } updateTitle(); updateAnalysis(); @@ -108,7 +122,18 @@ void MussaWindow::setAnalysis(MussaRef new_analysis) if (new_analysis != 0) { // only switch mussas if we loaded without error clear(); + //std::cout << "analysis soft: " << analysis->get_soft_threshold() + // << " new analysis soft: " << new_analysis->get_soft_threshold() + // << "\n"; analysis.swap(new_analysis); + //std::cout << "after swap soft thres: " << analysis->get_soft_threshold() + // << "\n"; + threshold->disconnect(this); + threshold->reset(analysis->get_threshold(), + analysis->get_window(), + analysis->get_soft_threshold()); + connect(threshold, SIGNAL(thresholdChanged(int)), + this, SLOT(setSoftThreshold(int))); updateTitle(); updateAnalysis(); } @@ -130,10 +155,11 @@ void MussaWindow::setupActions() connect(closeAction, SIGNAL(triggered()), this, SLOT(close())); closeAction->setIcon(QIcon(":/icons/exit.png")); - createNewAnalysisAction = new QAction(tr("Create Analysis"), this); + createNewAnalysisAction = new QAction(tr("Create &New Analysis"), this); connect(createNewAnalysisAction, SIGNAL(triggered()), this, SLOT(createNewAnalysis())); createNewAnalysisAction->setIcon(QIcon(":/icons/filenew.png")); + createNewAnalysisAction->setShortcut(Qt::CTRL | Qt::Key_N); createSubAnalysisAction = new QAction(tr("Add to Subanalysis"), this); connect(createSubAnalysisAction, SIGNAL(triggered()), @@ -143,6 +169,7 @@ void MussaWindow::setupActions() connect(saveAnalysisAction, SIGNAL(triggered()), this, SLOT(saveAnalysis())); saveAnalysisAction->setIcon(QIcon(":/icons/filesave.png")); + saveAnalysisAction->setShortcut(Qt::CTRL | Qt::Key_S); saveAnalysisAsAction = new QAction(tr("Save Analysis &As"), this); connect(saveAnalysisAsAction, SIGNAL(triggered()), @@ -152,7 +179,7 @@ void MussaWindow::setupActions() editMotifsAction = new QAction(tr("Edit Motifs"), this);; connect(editMotifsAction, SIGNAL(triggered()), this, SLOT(editMotifs())); - loadMotifListAction = new QAction(tr("Load Motif List"), this); + loadMotifListAction = new QAction(tr("Open Motif List"), this); connect(loadMotifListAction, SIGNAL(triggered()), this, SLOT(loadMotifList())); loadMotifListAction->setIcon(QIcon(":/icons/fileopen.png")); @@ -162,15 +189,16 @@ void MussaWindow::setupActions() this, SLOT(loadMupa())); loadMupaAction->setIcon(QIcon(":/icons/fileopen.png")); - loadSavedAnalysisAction = new QAction(tr("Load Existing &Analysis"), this); + loadSavedAnalysisAction = new QAction(tr("&Open Existing &Analysis"), this); connect(loadSavedAnalysisAction, SIGNAL(triggered()), this, SLOT(loadSavedAnalysis())); loadSavedAnalysisAction->setIcon(QIcon(":/icons/fileopen.png")); + loadSavedAnalysisAction->setShortcut(Qt::CTRL | Qt::Key_O); mussaManualAssistantAction = new QAction(tr("Mussagl Manual..."), this); mussaManualAssistantAction->setIcon(QIcon(":/icons/contents.png")); connect(mussaManualAssistantAction, SIGNAL(triggered()), - this, SLOT(showManual())); + this, SLOT(showManual())); newMussaWindowAction = new QAction(tr("&New Mussa Window"), this); newMussaWindowAction->setStatusTip("open another mussa window to allow comparing results"); @@ -200,9 +228,11 @@ void MussaWindow::setupActions() //Save pixel map action saveBrowserPixmapAction = new QAction(tr("Save to image..."), this); - connect(saveBrowserPixmapAction, (SIGNAL(triggered())), - browser, SLOT(promptSaveBrowserPixmap())); - saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png")); + if (browser) { + connect(saveBrowserPixmapAction, (SIGNAL(triggered())), + browser, SLOT(promptSaveBrowserPixmap())); + saveBrowserPixmapAction->setIcon(QIcon(":/icons/image2.png")); + } viewMussaAlignmentAction = new QAction(tr("View sequence alignment"), this); connect(viewMussaAlignmentAction, SIGNAL(triggered()), @@ -249,8 +279,10 @@ void MussaWindow::setupMainMenu() newMenu = menuBar()->addMenu(tr("&Edit")); newMenu->addAction(editMotifsAction); - newMenu->addAction(browser->getCopySelectedSequenceAsFastaAction()); + if (browser) newMenu->addAction(browser->getCopySelectedSequenceAsStringAction()); + if (browser) newMenu->addAction(browser->getCopySelectedSequenceAsFastaAction()); newMenu->addAction(createSubAnalysisAction); + if (browser) newMenu->addAction(browser->getEditSequencePropertiesAction()); newMenu = menuBar()->addMenu(tr("&View")); newMenu->addAction(viewMussaAlignmentAction); @@ -263,16 +295,29 @@ void MussaWindow::setupMainMenu() newMenu->addAction(aboutAction); // add some extra features to the context menu - QMenu *popupMenu = browser->getPopupMenu(); - if (popupMenu) { - popupMenu->addAction(viewMussaAlignmentAction); - popupMenu->addAction(createSubAnalysisAction); + if (browser) { + QMenu *popupMenu = browser->getPopupMenu(); + if (popupMenu) { + popupMenu->addAction(viewMussaAlignmentAction); + popupMenu->addAction(createSubAnalysisAction); + } } } +void MussaWindow::setupWidgets() +{ + setup_analysis_dialog = new MussaSetupDialog; + subanalysis_window.reset(new SubanalysisWindow(analysis)); + browser = new SequenceBrowserWidget(default_dir); + mussaViewTB = new QToolBar("Path Views", this); + zoom = new ZoomWidget(mussaViewTB); + threshold = new ThresholdWidget(mussaViewTB); +} + void MussaWindow::setupAssistant() { #if defined(QT_QTASSISTANT_FOUND) + /* QStringList manualAssistantArgs; manualAssistantArgs = QStringList(); manualAssistantArgs << "-profile" << "./doc/manual/mussagl_manual.adp"; @@ -280,6 +325,7 @@ void MussaWindow::setupAssistant() manualAssistant->setArguments(manualAssistantArgs); connect(manualAssistant, SIGNAL(error(QString)), this, SLOT(assistantError(QString))); + */ #endif } @@ -292,6 +338,9 @@ void MussaWindow::about() msg += "Version: "; msg += mussa_version; msg += "\n"; + msg += "Qt: "; + msg += qVersion(); + msg += "\n"; msg += "OpenGL: "; msg += (char *)glGetString(GL_VERSION); msg += "\n"; @@ -300,6 +349,11 @@ void MussaWindow::about() void MussaWindow::clear() { + if (motif_editor != 0) { + motif_editor->hide(); + delete motif_editor; + } + aligned_windows.clear(); browser->clear(); } @@ -435,13 +489,11 @@ bool MussaWindow::isClearingAnalysisSafe() void MussaWindow::editMotifs() { - if (motif_editor != 0) { - motif_editor->hide(); - delete motif_editor; + if (not motif_editor) { + motif_editor = new MotifEditor(analysis); + connect(motif_editor, SIGNAL(changedMotifs()), + this, SLOT(updateAnnotations())); } - motif_editor = new MotifEditor(analysis); - connect(motif_editor, SIGNAL(changedMotifs()), - this, SLOT(updateAnnotations())); motif_editor->show(); } @@ -520,10 +572,10 @@ void MussaWindow::loadMupa() // but this should work for the moment. if (not isClearingAnalysisSafe()) return; - MussaRef m(new Mussa); + MussaRef m = Mussa::init(); fs::path converted_path(mupa_path.toStdString(), fs::native); - connect(m.get(), SIGNAL(progress(const std::string&, int, int)), - this, SLOT(updateProgress(const std::string&, int, int))); + connect(m.get(), SIGNAL(progress(const QString&, int, int)), + this, SLOT(updateProgress(const QString&, int, int))); m->load_mupa_file(converted_path); m->analyze(); setAnalysis(m); @@ -557,10 +609,10 @@ void MussaWindow::loadSavedAnalysis() // but this should work for the moment. if (not isClearingAnalysisSafe()) return; - MussaRef m(new Mussa); + MussaRef m = Mussa::init(); fs::path converted_path(muway_dir.toStdString(), fs::native); - connect(m.get(), SIGNAL(progress(const std::string&, int, int)), - this, SLOT(updateProgress(const std::string&, int, int))); + connect(m.get(), SIGNAL(progress(const QString&, int, int)), + this, SLOT(updateProgress(const QString&, int, int))); m->load(converted_path); // only switch mussas if we loaded without error if (analysis->empty()) { @@ -574,6 +626,12 @@ void MussaWindow::loadSavedAnalysis() win->default_dir->setPath(converted_path.branch_path().native_directory_string().c_str()); win->show(); } + } catch (boost::filesystem::filesystem_error e) { + QString msg("Unable to load "); + msg += muway_dir; + msg += "\n"; + msg += e.what(); + QMessageBox::warning(this, "Load Parameter", msg); } catch (mussa_load_error e) { QString msg("Unable to load "); msg += muway_dir; @@ -586,22 +644,28 @@ void MussaWindow::loadSavedAnalysis() void MussaWindow::newMussaWindow() { - MussaRef a(new Mussa); - MussaWindow *win = new MussaWindow(a); + MussaWindow *win = new MussaWindow(Mussa::init()); win->default_dir = default_dir; win->show(); } void MussaWindow::setSoftThreshold(int value) { + //std::cout << "Soft: " << analysis->get_soft_threshold() + // << " Value: " << value << "\n"; if (analysis->get_soft_threshold() != value) { threshold->setEnabled( false ); + //std::cout << "Updating!!!!\n"; analysis->set_soft_threshold(value); analysis->nway(); updateLinks(); update(); threshold->setEnabled( true ); } + //else + //{ + // std::cout << "NOT Updating!!!!\n"; + //} } void MussaWindow::showMussaToolbar() @@ -612,6 +676,16 @@ void MussaWindow::showMussaToolbar() mussaViewTB->show(); } +void MussaWindow::showBasePairsCopied(size_t bp_copied) +{ + QString msg("Copied "); + QString num; + num.setNum(bp_copied); + msg += num + " base pairs"; + statusBar()->showMessage(msg, 5000); +} + + void MussaWindow::toggleMotifs() { NotImplementedBox(); @@ -620,22 +694,35 @@ void MussaWindow::toggleMotifs() void MussaWindow::showManual() { #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); + + // Only define the process once. + if (!assistantProcess) + assistantProcess = new QProcess(this); + + // No need to fire up the process again if it is already running. + if (assistantProcess->state() == QProcess::Running) + return; + + QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + + QLatin1String("/assistant"); + + assistantProcess->start(app, QStringList() << QLatin1String("-enableRemoteControl") + << QLatin1String("-collectionFile") << QLatin1String("mussagl_manual.qhc")); + if (!assistantProcess->waitForStarted()) { + QMessageBox::critical(this, tr("Remote Control"), + tr("Could not start Qt Assistant from %1.").arg(app)); + return; } + + // show index page + QTextStream str(assistantProcess); + str << QLatin1String("SetSource qthelp://edu.caltech.woldlab.mussagl.1_0_0/doc/mussagl_manual.html;") + << QLatin1String("expandToc 0") + << QLatin1Char('\0') << endl; + #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(); + QUrl manual_url("http://woldlab.caltech.edu/~king/mussagl_manual/"); + if (not QDesktopServices::openUrl(manual_url)) { QMessageBox::warning(this, tr("Mussa Help Error"), tr("Unable to launch webbrowser"), @@ -689,6 +776,7 @@ void MussaWindow::updateAnalysis() // 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()); + threshold->setBasepairThreshold(analysis->get_soft_threshold()); updateLinks(); browser->zoomOut(); zoom->setValue(browser->zoom()); @@ -753,7 +841,7 @@ void MussaWindow::updateLinks() } void -MussaWindow::updateProgress(const string& description, int current, int max) +MussaWindow::updateProgress(const QString& description, int current, int max) { // if we're done if (current == max) { @@ -765,9 +853,8 @@ MussaWindow::updateProgress(const string& description, int current, int max) } else { // if we're starting, create the dialog if (progress_dialog == 0) { - QString desc(description.c_str()); QString cancel("Cancel"); - progress_dialog = new QProgressDialog(desc, cancel, current, max, this); + progress_dialog = new QProgressDialog(description, cancel, current, max, this); progress_dialog->show(); } else { // just update the dialog @@ -777,9 +864,16 @@ MussaWindow::updateProgress(const string& description, int current, int max) qApp->processEvents(); } +void MussaWindow::updateAnalysisModified(bool is_modified) +{ + setWindowModified(is_modified); +} + void MussaWindow::updateTitle() { if (analysis) { - setWindowTitle(analysis->get_title().c_str()); + QString title(analysis->get_title().c_str()); + title += "[*]"; + setWindowTitle(title); } }