From: Diane Trout Date: Sat, 3 Jun 2006 01:58:40 +0000 (+0000) Subject: use Qt Signals & Slots for progress tracking X-Git-Url: http://woldlab.caltech.edu/gitweb/?p=mussa.git;a=commitdiff_plain;h=9b3c74c91e20cfa82a3f4f093ae676a10b8e78d0 use Qt Signals & Slots for progress tracking this replaces my first attempt that used boost signals (which is now removed from the repository). Mussa and NwayPaths now inherit from QObject and can emit a progress signal to give some indication of how far they've gotten at long running tasks. Though I don't have a solution for long running seqcomps yet. Also instead of hard coding a % constant to cut down on the number of calls to emit the signal, I should use some kind of timer. --- diff --git a/alg/CMakeLists.txt b/alg/CMakeLists.txt index c79b59b..07c4fea 100644 --- a/alg/CMakeLists.txt +++ b/alg/CMakeLists.txt @@ -1,5 +1,16 @@ +FIND_PACKAGE(OpenGL ) +FIND_PACKAGE(Boost REQUIRED) +FIND_PACKAGE(Qt4) +INCLUDE( ${QT_USE_FILE} ) + ADD_SUBDIRECTORY( test ) +SET(MOC_HEADERS + mussa.hpp + nway_paths.hpp + ) +QT4_WRAP_CPP(MOC_SOURCES ${MOC_HEADERS}) + SET(SOURCES annotation_colors.cpp color.cpp conserved_path.cpp @@ -14,13 +25,12 @@ SET(SOURCES annotation_colors.cpp parse_options.cpp sequence.cpp) -FIND_PACKAGE(OpenGL ) -FIND_PACKAGE(Boost REQUIRED) - -ADD_LIBRARY( mussa_core STATIC ${SOURCES} ) +ADD_LIBRARY( mussa_core STATIC ${SOURCES} ${MOC_SOURCES}) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${BOOST_INCLUDE_DIR}) -TARGET_LINK_LIBRARIES(mussa_core ${OPEN_gl_LIBRARY}) +TARGET_LINK_LIBRARIES(mussa_core + ${OPEN_gl_LIBRARY} + ${QT_LIBRARIES}) # these are really only needed for gcc on AMD64 SET_SOURCE_FILES_PROPERTIES(${SOURCES} PROPERTIES COMPILE_FLAGS "-fPIC") diff --git a/alg/flp.cpp b/alg/flp.cpp index 88ff209..56a0a08 100644 --- a/alg/flp.cpp +++ b/alg/flp.cpp @@ -44,6 +44,13 @@ FLPs::FLPs() : { } +FLPs::FLPs(const FLPs& o) : + window_size(o.window_size), + hard_threshold(o.hard_threshold), + all_matches(o.all_matches) +{ +} + void FLPs::setup(int win_size, int hard_thres) { diff --git a/alg/flp.hpp b/alg/flp.hpp index 0f5f892..4951213 100644 --- a/alg/flp.hpp +++ b/alg/flp.hpp @@ -13,7 +13,6 @@ // ---------------------------------------- // ---------- flp.hh ----------- // ---------------------------------------- - #include #include @@ -27,8 +26,9 @@ */ class FLPs { - public: +public: FLPs(); + FLPs(const FLPs& ); //! Setup a FLP and reserve space for the match lists /*! * Initialize the all_matches structure with a list of matches diff --git a/alg/flp_seqcomp.cpp b/alg/flp_seqcomp.cpp index 6db57bc..003d3fb 100644 --- a/alg/flp_seqcomp.cpp +++ b/alg/flp_seqcomp.cpp @@ -69,7 +69,7 @@ FLPs::seqcomp(string sseq1, string sseq2, bool is_RC) // this does the "upper diagonals" of the search // loop thru the start positions for sequence 1 - for(start_i = 0; start_i < size(); start_i++) + for(start_i = 0; start_i != size(); start_i++) { matches = 0; // compare initial window diff --git a/alg/mussa.cpp b/alg/mussa.cpp index 0dabf5b..26ff98a 100644 --- a/alg/mussa.cpp +++ b/alg/mussa.cpp @@ -11,6 +11,7 @@ // ---------------------------------------- // ---------- mussa_class.cc ----------- // ---------------------------------------- + #include #include namespace fs = boost::filesystem; @@ -24,14 +25,12 @@ namespace fs = boost::filesystem; using namespace std; -void callback(const std::string& desc, int cur, int end) -{ - std::cout << "analysis:" << desc << " " << cur << "/" << end << std::endl; -} Mussa::Mussa() { clear(); + connect(&the_paths, SIGNAL(progress(const std::string&, int, int)), + this, SIGNAL(progress(const std::string&, int, int))); } Mussa::Mussa(const Mussa& m) @@ -42,10 +41,11 @@ Mussa::Mussa(const Mussa& m) ana_mode(m.ana_mode), win_append(m.win_append), thres_append(m.thres_append), - analysis_cb(m.analysis_cb), motif_sequences(m.motif_sequences), color_mapper(m.color_mapper) { + connect(&the_paths, SIGNAL(progress(const std::string&, int, int)), + this, SIGNAL(progress(const std::string&, int, int))); } // set all parameters to null state @@ -59,9 +59,9 @@ Mussa::clear() soft_thres = 0; win_append = false; thres_append = false; - analysis_cb = callback; motif_sequences.clear(); color_mapper.clear(); + the_paths.clear(); } // these 5 simple methods manually set the parameters for doing an analysis @@ -87,17 +87,6 @@ Mussa::size() const return 0; } - -void Mussa::set_analysis_callback(analysis_callback cb) -{ - analysis_cb = cb; -} - -analysis_callback Mussa::get_analysis_calback() const -{ - return analysis_cb; -} - void Mussa::set_window(int a_window) { @@ -443,7 +432,6 @@ Mussa::analyze() end = time(NULL); totaltime = difftime(end, begin); - //cout << "seqload\tseqcomp\tnway\tsave\ttotal\n"; //cout << seqloadtime << "\t"; //cout << seqcomptime << "\t"; @@ -467,11 +455,12 @@ Mussa::seqcomp() for(vector::size_type i2 = 0; i2 < the_seqs.size(); i2++) all_comps[i].push_back(dummy_comp); } - for(vector::size_type i = 0; i < the_seqs.size(); i++) + for(vector::size_type i = 0; i < the_seqs.size(); i++) { seq_lens.push_back(the_seqs[i].size()); - + } int seqcomps_done = 0; int seqcomps_todo = (the_seqs.size() * (the_seqs.size()-1)) / 2; + emit progress("seqcomp", seqcomps_done, seqcomps_todo); for(vector::size_type i = 0; i < the_seqs.size(); i++) for(vector::size_type i2 = i+1; i2 < the_seqs.size(); i2++) @@ -481,9 +470,7 @@ Mussa::seqcomp() all_comps[i][i2].seqcomp(the_seqs[i].get_seq(), the_seqs[i2].get_seq(), false); all_comps[i][i2].seqcomp(the_seqs[i].get_seq(),the_seqs[i2].rev_comp(),true); ++seqcomps_done; - if (analysis_cb) { - analysis_cb("seqcomp", seqcomps_done, seqcomps_todo); - } + emit progress("seqcomp", seqcomps_done, seqcomps_todo); } } @@ -493,7 +480,6 @@ Mussa::nway() vector some_Seqs; the_paths.set_soft_threshold(soft_thres); - the_paths.set_progress_callback(analysis_cb); if (ana_mode == TransitiveNway) { the_paths.trans_path_search(all_comps); diff --git a/alg/mussa.hpp b/alg/mussa.hpp index cfb9ece..55547ec 100644 --- a/alg/mussa.hpp +++ b/alg/mussa.hpp @@ -13,6 +13,8 @@ // ---------------------------------------- // ---------- mussa_class.hh ----------- // ---------------------------------------- +#include + #include #include @@ -28,9 +30,15 @@ std::string int_to_str(int an_int); -class Mussa +class Mussa : public QObject { - public: + Q_OBJECT + +signals: + //! call whatever signaling system we want + void progress(const std::string& description, int cur, int max); + +public: enum analysis_modes { TransitiveNway, RadialNway, EntropyNway, RecursiveNway }; @@ -63,9 +71,6 @@ class Mussa */ int size() const; - void set_analysis_callback(analysis_callback cb); - analysis_callback get_analysis_calback() const; - //! set number of bases for this window size void set_window(int a_window); //! get number of bases for the sliding window @@ -174,8 +179,6 @@ class Mussa bool win_append; //! should we append _t to the saved analysis bool thres_append; - //! callback, periodically called as we run an analysis - analysis_callback analysis_cb; //! sequence data std::vector the_seqs; diff --git a/alg/nway_other.cpp b/alg/nway_other.cpp index 87ee972..08a19fd 100644 --- a/alg/nway_other.cpp +++ b/alg/nway_other.cpp @@ -251,10 +251,11 @@ NwayPaths::trans_path_search(vector > all_comparisons) all_matches); } } - if (progress_cb) { - progress_cb("transitive refinement", win_i, window_num); + if ((win_i % 1000) == 0) { + emit progress("transitive refinement", win_i, window_num); } } + emit progress("transitive refinement", window_num, window_num); //clog << "pathz=" << pathz.size() // << " all_cmp=" << all_comparisons.size(); //if (pathz.begin() != pathz.end()) diff --git a/alg/nway_paths.cpp b/alg/nway_paths.cpp index 419d5ed..7b085a0 100644 --- a/alg/nway_paths.cpp +++ b/alg/nway_paths.cpp @@ -26,18 +26,34 @@ namespace fs = boost::filesystem; using namespace std; NwayPaths::NwayPaths() - : progress_cb(0) { } +NwayPaths::NwayPaths(const NwayPaths &o) + : pathz(o.pathz), + refined_pathz(o.refined_pathz), + threshold(o.threshold), + win_size(o.win_size), + soft_thres(o.soft_thres), + ent_thres(o.ent_thres), + c_sequences(o.c_sequences) +{ +} + +void NwayPaths::clear() +{ + c_sequences.clear(); + pathz.clear(); + refined_pathz.clear(); +} + void NwayPaths::setup(int w, int t) { threshold = t; soft_thres = threshold; win_size = w; - progress_cb = 0; - pathz.clear(); + clear(); //cout << "nway: thres = " << threshold // << ", soft threo = " << soft_thres << endl; @@ -59,16 +75,6 @@ int NwayPaths::get_window() const return win_size; } -void NwayPaths::set_progress_callback(analysis_callback cb) -{ - progress_cb = cb; -} - -analysis_callback NwayPaths::get_progress_callback() const -{ - return progress_cb; -} - // dumbly goes thru and combines path windows exactly adjacent (ie + 1 index) // doesn't deal with interleaved adjacency void @@ -127,15 +133,15 @@ NwayPaths::simple_refine() ext_path = *next_path; } } - if (progress_cb) { - progress_cb("refine", path_count-1, pathz.size()); - } + if ((path_count % 100) == 0) + emit progress("refine", path_count-1, pathz.size()); } } + // this mysterious call tells the dialog box that we're actually done + emit progress("refine", pathz.size(), pathz.size()); //cout << "r_path number is: " << refined_pathz.size() << endl; } - void NwayPaths::add_path(int threshold, vector& loaded_path) { diff --git a/alg/nway_paths.hpp b/alg/nway_paths.hpp index 6a1bec8..008b23f 100644 --- a/alg/nway_paths.hpp +++ b/alg/nway_paths.hpp @@ -13,6 +13,8 @@ // ---------------------------------------- // ---------- mussa_nway.hh ----------- // ---------------------------------------- +#include + #include #include @@ -21,36 +23,31 @@ #include "alg/conserved_path.hpp" #include "alg/flp.hpp" -#include "alg/mussa_callback.hpp" -class NwayPaths +class NwayPaths : public QObject { - friend class ConnView; - friend class SeqView; - protected: - int threshold; - size_t win_size; - int soft_thres; + Q_OBJECT - double ent_thres; - std::vector c_sequences; //used by entropy_path_search - analysis_callback progress_cb; +signals: + //! emit to indicate how much progress we've made + void progress(const std::string& description, int cur, int max); - public: +public: NwayPaths(); + NwayPaths(const NwayPaths&); + //! setup an nway comparison, initialize # of species, window size, //! threshold void setup(int w, int t); void setup_ent(double new_entropy_thres, std::vector some_Seqs); + //! clear out our path + void clear(); + //! set the score that a match must exceed inorder to be recorded as a path void set_soft_threshold(int soft_thres); //! return minimum threshold for this analysis int get_threshold() const; //! return window size used for this analysis int get_window() const; - //! set analysis progress callback - void set_progress_callback(analysis_callback cb); - //! get analysis progress callback - analysis_callback get_progress_callback() const; void radiate_path_search(std::vector > all_comparisons); void trans_path_search(std::vector > all_comparisons); @@ -89,5 +86,14 @@ class NwayPaths // simple std::list pathz; std::list refined_pathz; + +protected: + int threshold; + size_t win_size; + int soft_thres; + + double ent_thres; + std::vector c_sequences; //used by entropy_path_search + }; #endif diff --git a/py/mussa.cpp b/py/mussa.cpp index e8bcfb8..aecf2b1 100644 --- a/py/mussa.cpp +++ b/py/mussa.cpp @@ -1,6 +1,5 @@ #include - -using namespace boost::python; +namespace py = boost::python; #include "alg/mussa.hpp" @@ -8,7 +7,7 @@ void export_mussa() { void (Mussa::*load_mupa_string)(std::string) = &Mussa::load_mupa_file; - class_("Mussa") + py::class_("Mussa") .def("save", &Mussa::save) .def("load", &Mussa::load, "Load previous run analysis") .def("load_mupa", load_mupa_string, "Load mussa parameter file") @@ -25,11 +24,12 @@ void export_mussa() &Mussa::set_analysis_mode) .add_property("analysisModeName", &Mussa::get_analysis_mode_name) .def("analyze", &Mussa::analyze, "Run the analysis") - .def("paths", &Mussa::paths, return_internal_reference<>()) + .def("paths", &Mussa::paths, py::return_internal_reference<>()) //.def("sequences", &Mussa::sequences) - .def("addSequence", &Mussa::add_a_seq) ; + .def("addSequence", &Mussa::add_a_seq) + ; - enum_("analysis_modes") + py::enum_("analysis_modes") .value("TransitiveNway", Mussa::TransitiveNway ) .value("RadialNway", Mussa::RadialNway ) .value("EntropyNway", Mussa::EntropyNway ) diff --git a/py/nway_paths.cpp b/py/nway_paths.cpp index ee44e88..1ba4450 100644 --- a/py/nway_paths.cpp +++ b/py/nway_paths.cpp @@ -1,12 +1,12 @@ #include -using namespace boost::python; +namespace py = boost::python; #include "alg/nway_paths.hpp" void export_nway_paths() { - class_("NwayPaths") - .add_property("pathz", range(&NwayPaths::pbegin, &NwayPaths::pend)) - .add_property("refinedPathz", range(&NwayPaths::rpbegin, &NwayPaths::rpend)) ; + py::class_("NwayPaths") + .add_property("pathz", py::range(&NwayPaths::pbegin, &NwayPaths::pend)) + .add_property("refinedPathz", py::range(&NwayPaths::rpbegin, &NwayPaths::rpend)) ; } diff --git a/qui/MussaWindow.cpp b/qui/MussaWindow.cpp index 454c725..d12e982 100644 --- a/qui/MussaWindow.cpp +++ b/qui/MussaWindow.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -30,6 +31,7 @@ MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) : mussaViewTB("Path Views"), zoom(), threshold(), + progress_dialog(0), aboutAction(0), closeAction(0), createNewAnalysisAction(0), @@ -81,6 +83,8 @@ MussaWindow::MussaWindow(Mussa *analysis_, QWidget *parent) : 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))); updateAnalysis(); } @@ -89,6 +93,7 @@ MussaWindow::~MussaWindow() if (analysis != 0) delete analysis; aligned_windows.clear(); if (motif_editor != 0) delete motif_editor; + if (progress_dialog != 0) delete progress_dialog; if (aboutAction != 0) delete aboutAction; if (closeAction != 0) delete closeAction; @@ -351,6 +356,8 @@ void MussaWindow::loadMupa() try { Mussa *m = new Mussa; fs::path converted_path(mupa_path.toStdString(), fs::native); + connect(m, 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); @@ -378,6 +385,8 @@ void MussaWindow::loadSavedAnalysis() try { Mussa *m = new Mussa; fs::path converted_path(muway_dir.toStdString(), fs::native); + connect(m, 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); @@ -530,3 +539,29 @@ void MussaWindow::updateLinks() browser.update(); } +void +MussaWindow::updateProgress(const string& description, int current, int max) +{ + // if we're done + if (current == max) { + cout << "done with dialog" << endl; + if (progress_dialog != 0) { + progress_dialog->hide(); + delete progress_dialog; + progress_dialog = 0; + } + } else { + // if we're starting, create the dialog + if (progress_dialog == 0) { + cout << "creating dialog" << endl; + QString desc(description.c_str()); + QString cancel("Cancel"); + progress_dialog = new QProgressDialog(desc, cancel, current, max, this); + progress_dialog->show(); + } else { + // just update the dialog + progress_dialog->setValue(current); + } + } + qApp->processEvents(); +} diff --git a/qui/MussaWindow.hpp b/qui/MussaWindow.hpp index dd55d78..42c90a2 100644 --- a/qui/MussaWindow.hpp +++ b/qui/MussaWindow.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -59,6 +60,8 @@ public slots: void loadSavedAnalysis(); //! set the soft threshold used by the Nway_Path algorithm void setSoftThreshold(int thres); + //! update progress bar + void updateProgress(const std::string& description, int cur, int max); //! open a new mussa window so one can compare analyses void newMussaWindow(); @@ -87,6 +90,7 @@ protected: QToolBar mussaViewTB; ZoomWidget zoom; ThresholdWidget threshold; + QProgressDialog *progress_dialog; QAction *aboutAction; QAction *closeAction;