Implement UI for subanalysis mode
authorDiane Trout <diane@caltech.edu>
Sat, 1 Jul 2006 04:21:30 +0000 (04:21 +0000)
committerDiane Trout <diane@caltech.edu>
Sat, 1 Jul 2006 04:21:30 +0000 (04:21 +0000)
unfortunately its still only a read-only user interface but
the a user can select a sequence region, add it to our track display
and then either cancel or run the analysis.

It unfortunately blocks the UI while it runs, but there's not a whole lot
I can do about that.

While implementing this I added a number of unittests to make sure
that my sequence selection code workes.

23 files changed:
alg/glseqbrowser.cpp
alg/glseqbrowser.hpp
alg/sequence.cpp
alg/sequence.hpp
alg/sequence_location.cpp
alg/sequence_location.hpp
alg/test/test_glseqbrowser.cpp
alg/test/test_sequence.cpp
alg/test/test_sequence_location.cpp
alg/track_region.hpp [new file with mode: 0644]
py/sequence.cpp
qui/CMakeLists.txt
qui/MussaWindow.cpp
qui/SequenceLocationModel.cpp
qui/SequenceLocationModel.hpp
qui/SubanalysisWindow.cpp
qui/SubanalysisWindow.hpp
qui/motif_editor/MotifEditor.cpp
qui/seqbrowser/SequenceBrowserWidget.cpp
qui/seqbrowser/SequenceBrowserWidget.hpp
qui/test/CMakeLists.txt
qui/test/TestColorSharing.cpp [new file with mode: 0644]
qui/test/TestSequenceBrowser.cpp [new file with mode: 0644]

index 4e18733fbc7c7d7805593dfda8a6ea1d42276bd2..919508bcdd8a9cdb3dffe8564bdbae423bd8bdce 100644 (file)
@@ -399,11 +399,32 @@ GlSeqBrowser::link(const vector<int>& path, const vector<bool>& rc, int )
   ++pathid;
 }
 
+void GlSeqBrowser::setSelectedPaths(std::vector<int> paths)
+{
+  selected_paths.clear();
+  for(std::vector<int>::iterator itor = paths.begin();
+      itor != paths.end();
+      ++itor)
+  {
+    selected_paths.insert(*itor);
+  }
+}
+
 const set<int>& GlSeqBrowser::selectedPaths() const
 {
   return selected_paths;
 }
 
+void GlSeqBrowser::appendSelectedTrack(GLuint track, int start, int stop)
+{
+  selected_tracks.push_back(TrackRegion(track, start, stop));
+}
+
+list<TrackRegion> GlSeqBrowser::selectedTracks() const 
+{
+  return selected_tracks;
+}
+
 //! copy sequence from selected track using formating function
 template<class Item>
 void GlSeqBrowser::copySelectedTracks(std::list<Item>& result, 
@@ -436,7 +457,7 @@ void GlSeqBrowser::copySelectedTracksAsFasta(std::string& copy_buffer)
     static string formatter(const Sequence& seq, int left, int right)
     {
       stringstream s;
-      s << ">" << seq.get_header() 
+      s << ">" << seq.get_fasta_header() 
         << "|" << "subregion=" << left << "-" << right+1
         << std::endl
         << seq.subseq(left, right-left+1) << std::endl;
index fab880fdba11c1ecae442e23a76e96811de2d35b..b5be3a6743d9dbd4af377aef9435e7c0ee0a2673 100644 (file)
@@ -10,6 +10,7 @@
 #include "alg/sequence.hpp"
 #include "alg/glsequence.hpp"
 #include "alg/sequence_location.hpp"
+#include "alg/track_region.hpp"
 
 //! Manage rendering a collection of glSequences
 class GlSeqBrowser
@@ -81,8 +82,17 @@ public:
   void clear_links();
   //! define a path
   void link(const std::vector<int>& path, const std::vector<bool>& isRC, int length);
+  //! set selected paths (it'd be nice if this could be a templated function)
+  void setSelectedPaths(std::vector<int> c);
   //! returns the index of pathids based on order added by link
   const std::set<int>& selectedPaths() const;
+
+  //! set selected tracks (it'd be nice if this could be a templated function)
+  void appendSelectedTrack(GLuint track_index, int left, int right);
+
+  //! return list of selected tracks
+  std::list<TrackRegion> selectedTracks() const;
+
   //! copy sequence from selected track using formating function
   template<class Item>
   void copySelectedTracks(std::list<Item>& result, 
@@ -145,20 +155,6 @@ public:
   typedef std::vector<pair_segment_map> path_segment_map_vector;
   path_segment_map_vector path_segments;
 
-  struct TrackRegion
-  {
-    GLuint track_id;
-    int left;
-    int right;
-
-    TrackRegion():track_id(0), left(0), right(0) {};
-    TrackRegion(const TrackRegion& o)
-      : track_id(o.track_id), left(o.left), right(o.right) {}
-    TrackRegion(GLuint id, int l, int r)
-      : track_id(id), left(l), right(r) {}
-    void set(GLuint id, int l, int r) { track_id = id; left=l; right=r; };
-  };
-
 private:
   //! recalculate the viewable world
   /*! depending on the size of our canvas, our zoom level and
index ee0f9f7118d315be3c015a92646762d512f1b772..7523ab679f3278ab9c2a9446dfb3497b8f1949c9 100644 (file)
@@ -375,7 +375,7 @@ struct push_back_seq {
     //std::cout << "adding seq: " << name << " " << new_seq << std::endl;
     
     Sequence s(new_seq);
-    s.set_header(name);
+    s.set_fasta_header(name);
     seq_list.push_back(s);
   };
 };
@@ -438,16 +438,6 @@ Sequence::parse_annot(std::string data, int start_index, int end_index)
   find_sequences(query_seqs.begin(), query_seqs.end());
 }
 
-void Sequence::set_species(const std::string& name)
-{
-  species = name;
-}
-
-std::string Sequence::get_species() const
-{
-  return species;
-}
-
 void Sequence::add_annotation(const annot& a)
 {
   annots.push_back(a);
@@ -466,7 +456,7 @@ Sequence::subseq(int start, int count) const
     count = size()-start;
   }
   Sequence new_seq(std::string::substr(start, count));
-  new_seq.set_header(get_header());
+  new_seq.set_fasta_header(get_fasta_header());
   //new_seq.set_species(get_species());
 
   new_seq.motif_list = motif_list;
@@ -541,24 +531,38 @@ Sequence::rev_comp() const
   return rev_comp;
 }
 
-void Sequence::set_header(std::string header_)
+void Sequence::set_fasta_header(std::string header_)
 {
   header = header_;
 }
 
+void Sequence::set_species(const std::string& name)
+{
+  species = name;
+}
+
+std::string Sequence::get_species() const
+{
+  return species;
+}
+
+
 std::string
-Sequence::get_header() const
+Sequence::get_fasta_header() const
 {
   return header;
 }
 
-/*
-std::string 
-Sequence::species()
+std::string
+Sequence::get_name() const
 {
-  return species;
+  if (header.size() > 0) 
+    return header;
+  else if (species.size() > 0)
+    return species;
+  else
+    return "";
 }
-*/
 
 void
 Sequence::clear()
@@ -934,7 +938,7 @@ void Sequence::find_sequences(std::list<Sequence>::iterator start,
                               std::list<Sequence>::iterator end)
 {
   while (start != end) {
-    add_string_annotation(*start, start->get_header());
+    add_string_annotation(*start, start->get_fasta_header());
     ++start;
   }
 }
index 47813657f7f976174948bef1c4ba53d0c2320df6..eceb961c93a5752b5b248fb97d52a704cd3dcd84 100644 (file)
@@ -103,8 +103,6 @@ class Sequence : public std::string
     void add_annotation(const annot& a);
     const std::list<annot>& annotations() const;
     const std::list<motif>& motifs() const;
-    void set_species(const std::string &);
-    std::string get_species() const;
 
     //! return a subsequence, copying over any appropriate annotation
     Sequence subseq(int start=0, int count = std::string::npos) const;
@@ -114,8 +112,17 @@ class Sequence : public std::string
     //! clear the sequence and its annotations
     void clear();
 
-    void set_header(std::string header);
-    std::string get_header() const;
+    //! set species name
+    void set_species(const std::string &);
+    //! get species name
+    std::string get_species() const;
+    //! set the fasta header
+    void set_fasta_header(std::string header);
+    //! get the fasta header
+    std::string get_fasta_header() const;
+    //! get name (will return the first non-empty, of fasta_header, species)
+    std::string get_name() const;
+
     //! add a motif to our list of motifs
     //! \throws motif_normalize_error if there's something wrong with a_motif
     void add_motif(const Sequence& a_motif);
index cc92c2fd4a2447891605d22002b700ad9ae46b40..bb17e34fd5a334f96e5d71833d4dd7e79a975560 100644 (file)
@@ -45,6 +45,11 @@ const Sequence& SequenceLocation::getSequence() const
   return *sequence;
 }
 
+Sequence SequenceLocation::getSelectedSequence() const
+{
+  return sequence->subseq(left, count);
+}
+
 void SequenceLocation::setLeft(int l)
 {
   left = l;
index 12830f7a6e388aa595ccea38b59b8dbe2a33d510..31831ce96b316e7d28514b0de41892ff0ec00636 100644 (file)
@@ -12,7 +12,10 @@ class SequenceLocation {
     SequenceLocation(const SequenceLocation& );
     SequenceLocation& operator=(const SequenceLocation&);
 
+    //! get the sequence we're selecting from
     const Sequence& getSequence() const;
+    //! return the selected subsequence
+    Sequence getSelectedSequence() const;
     void setLeft(int l);
     int getLeft() const;
     void setCount(int c);
index 336d0052f6c7c0b4d15f82bb8e09ad8659a2c40e..ad183f079e7e0eeed4d54427847099a72fae1037 100644 (file)
@@ -86,3 +86,75 @@ BOOST_AUTO_TEST_CASE( glseqbrowser_center )
   BOOST_CHECK_EQUAL( gt.sequences()[1].x(), (gt.viewportCenter()-15)-path[1] );
   BOOST_CHECK_EQUAL( gt.sequences()[2].x(), (gt.viewportCenter()-15)-path[2] );
 }
+
+BOOST_AUTO_TEST_CASE( setSelectedPaths )
+{
+  string s0("AAGGCCTT");
+  string s1("TTGGCCAA");
+  string s2("GATTACAA");
+  Sequence seq0(s0);
+  Sequence seq1(s1);
+  Sequence seq2(s2);
+
+  GlSeqBrowser gt;
+  gt.push_sequence(seq0);
+  gt.push_sequence(seq1);
+  gt.push_sequence(seq2);
+
+  // make up some sample data
+  vector<bool> rc;
+  rc += false, false, false;
+  vector<int> path;
+                path += 1,1,1; gt.link(path, rc, 1);
+  path.clear(); path += 1,1,3; gt.link(path, rc, 1); 
+  path.clear(); path += 2,3,3; gt.link(path, rc, 1); 
+  path.clear(); path += 3,3,3; gt.link(path, rc, 1);
+
+  vector<int> selected;
+  selected += 1,4;
+  BOOST_CHECK_EQUAL( gt.selectedPaths().size(), 0 );
+  gt.setSelectedPaths(selected);
+  BOOST_CHECK_EQUAL( gt.selectedPaths().size(), selected.size() );
+  gt.clear_selection();
+  BOOST_CHECK_EQUAL( gt.selectedPaths().size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE( setSelectedTracks )
+{
+  string s0("AAGGCCTT");
+  string s1("TTGGCCAA");
+  string s2("GATTACAA");
+  Sequence seq0(s0);
+  Sequence seq1(s1);
+  Sequence seq2(s2);
+
+  GlSeqBrowser gt;
+  gt.push_sequence(seq0);
+  gt.push_sequence(seq1);
+  gt.push_sequence(seq2);
+
+
+  BOOST_CHECK_EQUAL( gt.selectedTracks().size(), 0 );
+  gt.appendSelectedTrack(0, 0, seq0.size());
+  gt.appendSelectedTrack(2, 0, seq2.size());
+  BOOST_CHECK_EQUAL( gt.selectedTracks().size(), 2 );
+
+  list<Sequence> selected_sequence;
+  BOOST_CHECK_EQUAL(selected_sequence.size(), 0);
+  gt.copySelectedTracksAsSequences(selected_sequence);
+  BOOST_CHECK_EQUAL(selected_sequence.size(), 2);
+  BOOST_CHECK_EQUAL(selected_sequence.front(), seq0);
+  BOOST_CHECK_EQUAL(selected_sequence.back(), seq2);
+
+  gt.clear_selection();
+  BOOST_CHECK_EQUAL( gt.selectedPaths().size(), 0);
+
+  gt.appendSelectedTrack(0, 0, 2);
+  list<SequenceLocation> seq_locs;
+  gt.copySelectedTracksAsSeqLocation(seq_locs);
+  BOOST_CHECK_EQUAL(seq_locs.size(), 1);
+  BOOST_CHECK_EQUAL(seq_locs.front().getSequence(), seq0);
+  BOOST_CHECK_EQUAL(seq_locs.front().getLeft(), 0);
+  BOOST_CHECK_EQUAL(seq_locs.front().getRight(), 2);
+
+}
index 812a7a3cd7f87888d7610c4b5d32c22cc7532ee7..c510739d43120e2706ba9e0b35d97bb0ca57c34b 100644 (file)
@@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE( sequence_load )
   s.load_fasta(seq_path);
   BOOST_CHECK_EQUAL(s.subseq(0, 5), "GGATC"); // first few chars of fasta file
   BOOST_CHECK_EQUAL(s.subseq(2, 3), "ATC");
-  BOOST_CHECK_EQUAL(s.get_header(), "gi|180579|gb|M21487.1|HUMCKMM1 Human "
+  BOOST_CHECK_EQUAL(s.get_fasta_header(), "gi|180579|gb|M21487.1|HUMCKMM1 Human "
                                     "muscle creatine kinase gene (CKMM), "
                                     "5' flank");
 }
@@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE( sequence_motifs )
   /* FIXME: enable this when i find a way of passing storing the motif name
   // does our annotation travel?
   Sequence motif_seq(m);
-  motif_seq.set_header("hi");
+  motif_seq.set_fasta_header("hi");
   s1.add_motif(motif_seq);
 
   BOOST_CHECK_EQUAL(s1.motifs().size(), 2);
@@ -397,3 +397,13 @@ BOOST_AUTO_TEST_CASE( out_operator )
   BOOST_CHECK_EQUAL( s, buf.str() );
 }
 
+BOOST_AUTO_TEST_CASE( get_name )
+{
+  Sequence seq("AAGGCCTT");
+
+  BOOST_CHECK_EQUAL( seq.get_name(), "" );
+  seq.set_species("hooman"); // anyone remember tradewars?
+  BOOST_CHECK_EQUAL( seq.get_name(), "hooman");
+  seq.set_fasta_header("fasta human");
+  BOOST_CHECK_EQUAL( seq.get_name(), "fasta human");
+}
index 715465214705da4c37622820577de334e936ac70..048a0bed93be44013e105511c549a31d939e3fdd 100644 (file)
@@ -31,4 +31,5 @@ BOOST_AUTO_TEST_CASE( memory_test )
   }
 
   BOOST_CHECK_EQUAL(sl->getSequence(), "AAGGCCTT");
+  BOOST_CHECK_EQUAL(sl->getSelectedSequence(), "AA");
 }
diff --git a/alg/track_region.hpp b/alg/track_region.hpp
new file mode 100644 (file)
index 0000000..2f2c672
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef TRACK_REGION_HPP_
+#define TRACK_REGION_HPP_
+
+struct TrackRegion
+{
+  GLuint track_id;
+  int left;
+  int right;
+
+  TrackRegion():track_id(0), left(0), right(0) {};
+  TrackRegion(const TrackRegion& o)
+    : track_id(o.track_id), left(o.left), right(o.right) {}
+  TrackRegion(GLuint id, int l, int r)
+    : track_id(id), left(l), right(r) {}
+  void set(GLuint id, int l, int r) { track_id = id; left=l; right=r; };
+};
+#endif
index 3bdca90781e3bd978a4a1704f54e2a9ccbcebd2f..695a8eae2e55111e2c55a9fe3f37c20157082008 100644 (file)
@@ -19,7 +19,7 @@ void export_sequence()
     .def("__str__", &seq_to_string)
     .def("size", &Sequence::size)
     .def("__len__", &Sequence::size)
-    .add_property("header", &Sequence::get_header, &Sequence::set_header)
+    .add_property("header", &Sequence::get_fasta_header, &Sequence::set_fasta_header)
     .add_property("species", &Sequence::get_species, &Sequence::set_species)
     .def("rcseq", &Sequence::rev_comp, return_value_policy<return_by_value>())
   ;
index 07c050aa47c4862e266e664d7033d902ebec6bee..324704ae705d730c40f2b16b1afffa82ef8d9b60 100644 (file)
@@ -30,7 +30,6 @@ SET(MOC_HEADERS
       mussa_setup_dialog/MussaSetupWidget.hpp
       mussa_setup_dialog/SequenceSetupFrame.hpp
       mussa_setup_dialog/SequenceSetupWidget.hpp
-      mussa_setup_dialog/SetupInfo.hpp
       seqbrowser/ScrollableSequenceBrowser.hpp
       seqbrowser/SequenceBrowser.hpp
       seqbrowser/SequenceBrowserSidebar.hpp
index 1ab227095d9a97395a1fcf6f125ceea3bb239f94..90fe7f39f557014e360b8eb414a915099194ee73 100644 (file)
@@ -21,6 +21,7 @@
 #include "mussa_exceptions.hpp"
 
 #include <memory>
+#include <iterator>
 #include <iostream>
 
 #include <boost/filesystem/path.hpp>
@@ -331,6 +332,16 @@ void MussaWindow::createNewAnalysis()
 
 void MussaWindow::createSubAnalysis()
 {
+  list<SequenceLocation> 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();
   }
index 727a79b10a10614dc2248c900d94dbf815b1644c..f724596e431438f6682cb063c46849e76dc2c766 100644 (file)
@@ -3,7 +3,6 @@
 SequenceLocationModel::SequenceLocationModel(QObject *parent) 
   : QAbstractTableModel(parent)
 {
-  Sequence s("AGCT");
 }
 
 void SequenceLocationModel::assign(
@@ -36,6 +35,15 @@ SequenceLocationModel::const_iterator SequenceLocationModel::begin() const
   return sequence_locations.begin();
 }
 
+void SequenceLocationModel::clear()
+{
+  if (sequence_locations.size() != 0) {
+    beginRemoveRows(QModelIndex(), 0, sequence_locations.size()-1);
+    sequence_locations.pop_back();
+    endRemoveRows();
+  }
+}
+
 SequenceLocationModel::iterator SequenceLocationModel::end()
 {
   return sequence_locations.end();
@@ -60,12 +68,20 @@ SequenceLocation& SequenceLocationModel::operator[](
 
 void SequenceLocationModel::pop_back()
 {
-  sequence_locations.pop_back();
+  int last_element = sequence_locations.size()-1;
+  if (last_element >= 0) {
+    beginRemoveRows(QModelIndex(), last_element, last_element);
+    sequence_locations.pop_back();
+    endRemoveRows();
+  } 
 }
 
 void SequenceLocationModel::push_back(SequenceLocation& item)
 {
+  int last_element = sequence_locations.size();
+  beginInsertRows(QModelIndex(), last_element, last_element);
   sequence_locations.push_back(item);
+  endInsertRows();
 }
 
 SequenceLocationModel::size_type SequenceLocationModel::size() const
@@ -100,13 +116,11 @@ SequenceLocationModel::data(const QModelIndex &index, int role) const
   if (role == Qt::DisplayRole) {
     if (index.column() == 0 ) {
       const Sequence& seq = sequence_locations[index.row()].getSequence();
-      std::string header(seq.get_header());
-      if (header.size() == 0) {
-        return QVariant(QString(tr("Sequence ")) + 
-                        QString().setNum(index.row())
-            );
+      std::string name(seq.get_name());
+      if (name.size() == 0) {
+        return QString(tr("Unnamed Sequence"));
       } else {
-        return QVariant(QString(header.c_str()));
+        return QVariant(QString(name.c_str()));
       }
     } else if (index.column() == 1) {
       return QVariant(sequence_locations[index.row()].getLeft());
@@ -120,24 +134,30 @@ SequenceLocationModel::data(const QModelIndex &index, int role) const
 QVariant 
 SequenceLocationModel::headerData(
     int section, 
-    Qt::Orientation orentation, 
+    Qt::Orientation orientation, 
     int role
-)
+) const
 {
-  switch(section) {
-    case 0:
-      return QString("Sequence");
-      break;
-    case 1:
-      return QString("Left");
-      break;
-    case 2:
-      return QString("Right");
-      break;
-    default:
-      return QVariant();
-      break;
+  if (role != Qt::DisplayRole)
+    return QVariant();
+
+  if (orientation == Qt::Horizontal) {
+    switch(section) {
+      case 0:
+        return QString("Sequence");
+        break;
+      case 1:
+        return QString("Left");
+        break;
+      case 2:
+        return QString("Right");
+        break;
+      default:
+        return QVariant();
+        break;
+    }
   }
+  return QVariant();
 }
 
 
index 76b933351e889b931da8e834133863e7a1104c48..7a4b0e782b80079808fc32b74a08e7d86adac750 100644 (file)
@@ -29,6 +29,8 @@ class SequenceLocationModel : public QAbstractTableModel
     iterator begin();
     //! return an iterator to the beginning of the model
     const_iterator begin() const;
+    //! empty the model
+    void clear();
     //! return an iterator to the end of the model
     iterator end();
     //! return an iterator to the end of the model
@@ -52,7 +54,7 @@ class SequenceLocationModel : public QAbstractTableModel
     int columnCount(const QModelIndex& parent=QModelIndex()) const;
     QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
 
-    QVariant headerData(int section, Qt::Orientation orentation, int role=Qt::DisplayRole);
+    QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const;
 
     //bool setData(const QModelIndex& index, const QVariant &value, 
     //             int role=Qt::EditRole);
index c6d0d13b71033438d405c4d02898a8df5ea22644..efed5de9526f6e8441a6de9702628c81f273665d 100644 (file)
@@ -1,27 +1,85 @@
 #include "qui/SubanalysisWindow.hpp"
+#include "qui/MussaWindow.hpp"
+
+#include "mussa_exceptions.hpp"
+#include "alg/mussa.hpp"
 
 #include <QVBoxLayout>
 #include <QHBoxLayout>
+#include <QGridLayout>
 
 SubanalysisWindow::SubanalysisWindow(QWidget *parent)
   : QWidget(parent),
+    window(0),
+    threshold(0),
     table(0),
     ok(0),
     cancel(0)
 {
-  //model.setStringList(string_list);
+  QGridLayout *parameterLayout = new QGridLayout;
 
-  QHBoxLayout *buttonLayout = new QHBoxLayout();
-  QVBoxLayout *verticalLayout = new QVBoxLayout();
+  QLabel *thresholdLabel = new QLabel(tr("threshold (bp)"));
+  parameterLayout->addWidget(thresholdLabel, 0, 0);
+  threshold = new QSpinBox(this);
+  threshold->setValue(8);
+  parameterLayout->addWidget(threshold, 1, 0);
+  QLabel *windowLabel = new QLabel(tr("window (bp)"));
+  parameterLayout->addWidget(windowLabel, 0, 1);
+  window = new QSpinBox(this);
+  window->setValue(10);
+  parameterLayout->addWidget(window, 1, 1);
 
   ok = new QPushButton(tr("&OK"), this);
+  connect(ok, SIGNAL(clicked()), this, SLOT(run()));
   cancel = new QPushButton(tr("Cancel"), this);
+  connect(cancel, SIGNAL(clicked()), this, SLOT(abort()));
   table = new QTableView(this);
   table->setModel(&model);
 
+  // layout buttons
+  QHBoxLayout *buttonLayout = new QHBoxLayout;
   buttonLayout->addWidget(ok);
   buttonLayout->addWidget(cancel);
+
+  // layout verticle space
+  QVBoxLayout *verticalLayout = new QVBoxLayout;
+  verticalLayout->addLayout(parameterLayout);
   verticalLayout->addWidget(table);
   verticalLayout->addLayout(buttonLayout);
   setLayout(verticalLayout);
 }
+
+SequenceLocationModel& SubanalysisWindow::getModel()
+{
+  return model;
+}
+
+void SubanalysisWindow::abort()
+{
+  model.clear();
+  hide();
+}
+
+void SubanalysisWindow::run()
+{
+  if (window == 0 or threshold == 0) 
+    throw std::runtime_error("SubanalysisWindow misconstructed");
+
+  std::auto_ptr<Mussa> m(new Mussa);
+
+  for(SequenceLocationModel::iterator itor = model.begin();
+      itor != model.end();
+      ++itor)
+  {
+    m->append_sequence(itor->getSelectedSequence());
+  }
+
+  m->set_window(window->value());
+  m->set_threshold(threshold->value());
+  m->analyze();
+  MussaWindow *mw = new MussaWindow(m.get());
+  mw->show();
+  model.clear();
+  hide();
+}
+
index 883dda800bb3163eeaad7fcd9991055d40808d22..b081d1d0e2d53bc9dc712052f53adf918d41c8fa 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <QTableView>
 #include <QPushButton>
+#include <QSpinBox>
 #include <QStringList>
 #include <QWidget>
 
@@ -15,7 +16,19 @@ class SubanalysisWindow : public QWidget
 public: 
   SubanalysisWindow(QWidget *parent = 0);
 
+  //! return a modifiable reference to our SequenceLocationModel
+  SequenceLocationModel& getModel();
+
+public slots:
+  //! clear our model and close the window
+  void abort();
+
+  //! create a subanalysis and run it
+  void run();
+
 private:  
+  QSpinBox *window;
+  QSpinBox *threshold;
   QTableView *table;
   QPushButton *ok;
   QPushButton *cancel;
index 12a1e9e2e291cf58bbd46d1f1196c20fbf4203c8..0fd80f09e628f3337dc18c534e3d2f574c144cb8 100644 (file)
@@ -56,7 +56,7 @@ void MotifEditor::updateMotifs()
   {
     if ((*md_i)->motif().size() > 0 && (*md_i)->enabled()) {
       Sequence new_motif((*md_i)->motif());
-      new_motif.set_header((*md_i)->name());
+      new_motif.set_fasta_header((*md_i)->name());
       motifs.push_back((*md_i)->motif());
       colors.push_back((*md_i)->color());
     }
index 7ed2b4de31d5c0cfc6447aa02312880d4521b9fb..0f396f2f27126eebe48eb6778e273e76dba75572 100644 (file)
@@ -57,6 +57,13 @@ void SequenceBrowserWidget::copySelectedSequenceAsFasta()
   scrollable_browser.browser().copySelectedSequenceAsFasta();
 }
 
+void SequenceBrowserWidget::copySelectedTracksAsSeqLocation(
+    std::list<SequenceLocation>& locations
+)
+{
+  scrollable_browser.browser().copySelectedTracksAsSeqLocation(locations);
+}
+
 void SequenceBrowserWidget::setSequences(
     const std::vector< boost::shared_ptr<Sequence> >& sequences,
     boost::shared_ptr<AnnotationColors> cm)
index 0fa7bdac3a0e709ff3ee763d94ffdb7a004a0675..6c82f58b862d554a515a804ec8beb4aaaa3dc6f7 100644 (file)
@@ -24,6 +24,9 @@ public:
   //! return our copy actioy (reference stored internally)
   QAction &getCopySelectedSequenceAsFastaAction();
 
+  //! copy selected track regions into a list of SequenceLocations
+  void copySelectedTracksAsSeqLocation(std::list<SequenceLocation>& );
+
   //! return current zoom size
   double zoom();
 
index 13d74df20b10d41c8b9a6b8d78cc99a67f0af3df..eaa68a9f577493137cbf160b05c50c0b0b6ebba9 100644 (file)
@@ -38,3 +38,5 @@ MACRO(MAKE_UNITTEST basename)
 ENDMACRO(MAKE_UNITTEST)
 
 MAKE_UNITTEST(TestSequenceLocationModel)
+MAKE_UNITTEST(TestSequenceBrowser)
+MAKE_UNITTEST(TestColorSharing)
diff --git a/qui/test/TestColorSharing.cpp b/qui/test/TestColorSharing.cpp
new file mode 100644 (file)
index 0000000..5730aca
--- /dev/null
@@ -0,0 +1,30 @@
+#include <QtGui>
+#include <QtTest/QtTest>
+
+#include "alg/mussa.hpp"
+#include "alg/color.hpp"
+#include "qui/MussaWindow.hpp"
+
+//! do our colors get shared correctly between different windows?
+class TestColorSharing : public QObject
+{
+  Q_OBJECT
+
+private slots:
+
+  void simple2sequence() {
+    Color green(0.0, 1.0, 0.0);
+    Mussa m;
+    m.append_sequence("AAGGCCTT");
+    m.append_sequence("GGTTCCAA");
+    m.set_window(2);
+    m.set_threshold(2);
+    m.analyze();
+
+    //MussaWindow mw(&m);
+    m.add_motif("GG", green);
+  }
+};
+
+QTEST_MAIN(TestColorSharing)
+#include "moc_TestColorSharing.cxx"
diff --git a/qui/test/TestSequenceBrowser.cpp b/qui/test/TestSequenceBrowser.cpp
new file mode 100644 (file)
index 0000000..6925615
--- /dev/null
@@ -0,0 +1,49 @@
+#include <QtGui>
+#include <QtTest/QtTest>
+
+#include "alg/sequence.hpp"
+#include "qui/seqbrowser/SequenceBrowser.hpp"
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <boost/assign.hpp>
+using namespace boost::assign;
+
+
+class TestSequenceBrowser : public QObject
+{
+  Q_OBJECT
+
+private slots:
+
+  void testSimplePushSequence() {
+    Sequence seq1("AAGGCCTT");
+    Sequence seq2("GGCCTTAA");
+
+    SequenceBrowser browser;
+    QVERIFY(browser.sequences().size() == 0);
+    browser.push_sequence(seq1);
+    browser.push_sequence(seq2);
+    QVERIFY(browser.sequences().size() == 2);
+    browser.clear();
+    QVERIFY(browser.sequences().size() == 0);
+  }
+
+  void testSelect() {
+    Sequence seq1("AAGGCCTT");
+    Sequence seq2("GGCCTTAA");
+
+    SequenceBrowser browser;
+    browser.push_sequence(seq1);
+    browser.push_sequence(seq2);
+    std::vector<int> path; path += 1,1;
+    std::vector<bool> rc; rc += false, false;
+    browser.link(path, rc, 2);
+
+  }
+};
+
+QTEST_MAIN(TestSequenceBrowser)
+#include "moc_TestSequenceBrowser.cxx"