use Qt Signals & Slots for progress tracking
authorDiane Trout <diane@caltech.edu>
Sat, 3 Jun 2006 01:58:40 +0000 (01:58 +0000)
committerDiane Trout <diane@caltech.edu>
Sat, 3 Jun 2006 01:58:40 +0000 (01:58 +0000)
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.

13 files changed:
alg/CMakeLists.txt
alg/flp.cpp
alg/flp.hpp
alg/flp_seqcomp.cpp
alg/mussa.cpp
alg/mussa.hpp
alg/nway_other.cpp
alg/nway_paths.cpp
alg/nway_paths.hpp
py/mussa.cpp
py/nway_paths.cpp
qui/MussaWindow.cpp
qui/MussaWindow.hpp

index c79b59bc8b76cc9d2a4c4db85061c06dfeca75cf..07c4fea742e47ff9e41017c485697470221e0e4b 100644 (file)
@@ -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")
index 88ff209a9eeec64470ac7ce450c97e06a0484674..56a0a0828fa469a62637df8d858778ba212052a6 100644 (file)
@@ -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)
 {
index 0f5f892234ae4fac78093db0885bf8cad115191a..4951213968b039330999e6d4e6c427719fa1545a 100644 (file)
@@ -13,7 +13,6 @@
 //                        ----------------------------------------
 //                            ---------- flp.hh  -----------
 //                        ----------------------------------------
-
 #include <boost/filesystem/path.hpp>
 
 #include <list>
@@ -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
index 6db57bc9fb3347501fe72df3fe4a00d4e9821515..003d3fbb2ee55f2410820699cf6fb7705db493bc 100644 (file)
@@ -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
index 0dabf5b435274af524935f8654212c1f28d73a14..26ff98a8d9cef4a8bb213c1b0c8a8a2027981a9a 100644 (file)
@@ -11,6 +11,7 @@
 //                        ----------------------------------------
 //                          ---------- mussa_class.cc -----------
 //                        ----------------------------------------
+
 #include <boost/filesystem/operations.hpp>
 #include <boost/filesystem/fstream.hpp>
 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<Sequence>::size_type i2 = 0; i2 < the_seqs.size(); i2++)
       all_comps[i].push_back(dummy_comp);
   }
-  for(vector<Sequence>::size_type i = 0; i < the_seqs.size(); i++)
+  for(vector<Sequence>::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<Sequence>::size_type i = 0; i < the_seqs.size(); i++)
     for(vector<Sequence>::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<string> 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);
index cfb9ece6b95b9ef95d4ffce13283e8b9d03081b9..55547ec7cc3d60598b0f85a80da820d533aa15d8 100644 (file)
@@ -13,6 +13,8 @@
 //                        ----------------------------------------
 //                          ---------- mussa_class.hh -----------
 //                        ----------------------------------------
+#include <QObject> 
+
 #include <boost/filesystem/path.hpp>
 
 #include <list>
 
 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<threshold> to the saved analysis
     bool thres_append;
-    //! callback, periodically called as we run an analysis
-    analysis_callback analysis_cb;
 
     //! sequence data
     std::vector<Sequence> the_seqs;
index 87ee972e48a21d00c3495f401d15d4861db36b87..08a19fd620a91af6d779eb672402ba908e1cbcff 100644 (file)
@@ -251,10 +251,11 @@ NwayPaths::trans_path_search(vector<vector<FLPs> > 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())
index 419d5edfbf03441171fb3f32add1fdd8f609aced..7b085a0844860164b78ca8520b4294b5ffe14f63 100644 (file)
@@ -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<int>& loaded_path)
 {
index 6a1bec85eead18aac4afddc7693fc53df5d325d2..008b23f0730657842b7a97729789ee9d72a1753b 100644 (file)
@@ -13,6 +13,8 @@
 //                        ----------------------------------------
 //                         ----------  mussa_nway.hh  -----------
 //                        ----------------------------------------
+#include <QObject>
+
 #include <boost/filesystem/path.hpp>
 
 #include <list>
 
 #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<char *> 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<std::string> 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<std::vector<FLPs> > all_comparisons);
     void trans_path_search(std::vector<std::vector<FLPs> > all_comparisons);
@@ -89,5 +86,14 @@ class NwayPaths
     // simple
     std::list<ConservedPath> pathz;
     std::list<ConservedPath > refined_pathz;
+
+protected:
+    int threshold;
+    size_t win_size;
+    int soft_thres;
+
+    double ent_thres;
+    std::vector<char *> c_sequences; //used by entropy_path_search
+
 };
 #endif
index e8bcfb8a2ebcfc86a2f4836dd6ad17cd55b2468e..aecf2b146f928376e7c3073c8f045fbaa2b6fe45 100644 (file)
@@ -1,6 +1,5 @@
 #include <boost/python.hpp>
-
-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>("Mussa")
+  py::class_<Mussa>("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_<Mussa::analysis_modes>("analysis_modes")
+  py::enum_<Mussa::analysis_modes>("analysis_modes")
     .value("TransitiveNway", Mussa::TransitiveNway )
     .value("RadialNway", Mussa::RadialNway )
     .value("EntropyNway", Mussa::EntropyNway )
index ee44e88e413adf4030a2fa1cc7585097764c9b1b..1ba44500a099bbee6982773b558bc20d4609a4d5 100644 (file)
@@ -1,12 +1,12 @@
 #include <boost/python.hpp>
-using namespace boost::python;
+namespace py = boost::python;
 
 #include "alg/nway_paths.hpp"
 
 void export_nway_paths()
 {
-  class_<NwayPaths>("NwayPaths")
-    .add_property("pathz", range(&NwayPaths::pbegin, &NwayPaths::pend))
-    .add_property("refinedPathz", range(&NwayPaths::rpbegin, &NwayPaths::rpend)) ;
+  py::class_<NwayPaths>("NwayPaths")
+    .add_property("pathz", py::range(&NwayPaths::pbegin, &NwayPaths::pend))
+    .add_property("refinedPathz", py::range(&NwayPaths::rpbegin, &NwayPaths::rpend)) ;
 }
 
index 454c7253aa2d0f26c892ce70f8d7fc376de4e2b9..d12e982d8061326cd83d32fcbb821c41ed1a6746 100644 (file)
@@ -1,4 +1,5 @@
 #include <QAction>
+#include <QApplication>
 #include <QAssistantClient>
 #include <QDir>
 #include <QFileDialog>
@@ -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();
+}
index dd55d78baea369a1d81b66049d24276a02489a64..42c90a2ee59bd23cb3131881350c4d0aa6488af6 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <QMainWindow>
 #include <QPixmap>
+#include <QProgressDialog>
 #include <QSpinBox>
 #include <QToolBar>
 
@@ -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;