-#include "py/python.hpp"
#include "qui/MussaWindow.hpp"
#include "mussa_exceptions.hpp"
#include "version.hpp"
#include <QApplication>
#include <QAssistantClient>
#include <QCloseEvent>
+#include <QDesktopServices>
#include <QDir>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QStatusBar>
#include <QString>
#include <QStringList>
+#include <QUrl>
#include <QWhatsThis>
#include <memory>
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),
viewMussaAlignmentAction(0),
manualAssistant(0)
{
+ init_resources();
+ setupWidgets();
setupActions();
- setupMainMenu();
setupAssistant();
+ setupMainMenu();
+
+ setWindowIcon(QIcon(":/icons/mussa.png"));
+ default_dir.reset(new QDir(QDir::home().absolutePath()));
- //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)));
-
- // 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)));
+ mussaViewTB->addWidget(zoom);
+
+ // threshold range is set in updateAnalysis
connect(threshold, SIGNAL(thresholdChanged(int)),
this, SLOT(setSoftThreshold(int)));
mussaViewTB->addWidget(threshold);
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();
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");
//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()),
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);
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)
msg += "Version: ";
msg += mussa_version;
msg += "\n";
+ msg += "Qt: ";
+ msg += qVersion();
+ msg += "\n";
msg += "OpenGL: ";
msg += (char *)glGetString(GL_VERSION);
msg += "\n";
void MussaWindow::clear()
{
+ if (motif_editor != 0) {
+ motif_editor->hide();
+ delete motif_editor;
+ }
+
aligned_windows.clear();
browser->clear();
}
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();
}
// 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);
// 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()) {
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;
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();
}
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();
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();
+ 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"),
}
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) {
} 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
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);
}
}