#include <map>
#include <string>
+#include <boost/shared_ptr.hpp>
+
#include "color.hpp"
#include "sequence.hpp"
color_map_type cm;
};
+class AnnotationColors;
+typedef boost::shared_ptr<AnnotationColors> AnnotationColorsRef;
+
class AnnotationColors
{
public:
return zoom_level;
}
-void GlSeqBrowser::setColorMapper(boost::shared_ptr<AnnotationColors> cm)
+void GlSeqBrowser::setColorMapper(AnnotationColorsRef cm)
{
color_mapper = cm;
}
-const AnnotationColors& GlSeqBrowser::colorMapper()
+const AnnotationColorsRef GlSeqBrowser::colorMapper()
{
- return *color_mapper;
+ return color_mapper;
}
void GlSeqBrowser::clear()
path_segments.push_back(pair_segment_map());
}
-const std::vector<boost::shared_ptr<GlSequence> >& GlSeqBrowser::sequences() const
+const std::vector<GlSequenceRef >& GlSeqBrowser::sequences() const
{
return track_container;
}
void centerOnPath(const std::vector<int>&);
void setColorMapper(boost::shared_ptr<AnnotationColors> cm);
- const AnnotationColors& colorMapper();
+ const AnnotationColorsRef colorMapper();
//! clear our tracks and connections
void clear();
//! the center of our current viewport (world coord) (used for scrollbar)
float viewport_center;
double zoom_level;
- boost::shared_ptr<AnnotationColors> color_mapper;
+ AnnotationColorsRef color_mapper;
//! counter for each path added to us via connect
int pathid;
protected:
//! container of all the GlSequences loaded into our scene
- std::vector<boost::shared_ptr<GlSequence> > track_container;
+ std::vector<GlSequenceRef > track_container;
//! where to draw our box (world coordinates)
rect<float> selectedRegion;
//! true if we have a selection
// draw annotations
GLfloat annotation_z = z() + 10.0;
const std::list<annot>& annots = Sequence::annotations();
- const std::list<motif>& motifs = Sequence::motifs();
+ const MotifList& motifs = Sequence::motifs();
for (std::list<annot>::const_iterator annot_itor = annots.begin();
annot_itor != annots.end();
++annot_itor)
height(), annotation_z);
}
// if motifs?
- for (std::list<motif>::const_iterator motifs_itor = motifs.begin();
+ for (MotifList::const_iterator motifs_itor = motifs.begin();
motifs_itor != motifs.end();
++motifs_itor)
{
draw_box(left, right, x()+motifs_itor->begin, x()+motifs_itor->end,
height(), annotation_z+1.0);
}
-
}
// this way of drawing characters, came from the red open gl book
const ColorRef color() const;
//! return our draw color
ColorRef color();
+ //! return our annotation color mapper
+ AnnotationColorsRef colorMapper() { return color_mapper; }
//! draw a track
/*! left and right are the edges of the current viewport
friend bool operator==(const GlSequence &left, const GlSequence &right);
protected:
- boost::shared_ptr<AnnotationColors> color_mapper;
+ AnnotationColorsRef color_mapper;
const GLfloat char_pix_per_world_unit;
//! Return the pixel width of the opengl viewport.
{
// once we've loaded all the motifs from the file,
// lets attach them to the sequences
- for(vector<boost::shared_ptr<Sequence> >::iterator seq_i = the_seqs.begin();
+ for(vector<SequenceRef >::iterator seq_i = the_seqs.begin();
seq_i != the_seqs.end();
++seq_i)
{
Sequence::Sequence(const char *seq, AlphabetRef alphabet_, SeqSpan::strand_type strand_)
: header(""),
- species("")
+ species(""),
+ motif_list(new MotifList)
{
set_filtered_sequence(seq, alphabet_, 0, npos, strand_);
}
AlphabetRef alphabet_,
SeqSpan::strand_type strand_)
: header(""),
- species("")
+ species(""),
+ motif_list(new MotifList)
{
set_filtered_sequence(seq, alphabet_, 0, seq.size(), strand_);
}
Sequence::Sequence(const SeqSpanRef& seq_ref)
: seq(seq_ref),
header(""),
- species("")
+ species(""),
+ motif_list(new MotifList)
{
}
header.clear();
species.clear();
annots.clear();
- motif_list.clear();
+ motif_list.reset(new MotifList);
}
void
motif_start_i != motif_starts.end();
++motif_start_i)
{
- motif_list.push_back(motif(*motif_start_i, a_motif.get_sequence()));
+ motif_list->push_back(motif(*motif_start_i, a_motif.get_sequence()));
}
}
void Sequence::clear_motifs()
{
- motif_list.clear();
+ if (motif_list)
+ motif_list->clear();
+ else
+ motif_list.reset(new MotifList);
}
-const std::list<motif>& Sequence::motifs() const
+const Sequence::MotifList& Sequence::motifs() const
{
- return motif_list;
+ return *motif_list;
}
std::vector<int>
typedef SeqString::const_reference const_reference;
typedef SeqString::size_type size_type;
static const size_type npos = SeqString::npos;
+
+ typedef std::list<motif> MotifList;
+ typedef boost::shared_ptr<MotifList> MotifListRef;
Sequence(AlphabetRef a = reduced_dna_alphabet);
Sequence(const char* seq,
//! add an annotation to our list of annotations
void add_annotation(const annot& a);
const std::list<annot>& annotations() const;
- const std::list<motif>& motifs() const;
+ const MotifList& motifs() const;
//! add a motif to our list of motifs
void add_motif(const Sequence& a_motif);
//! store our oldstyle annotations
std::list<annot> annots;
//! a seperate list for motifs since we're currently not saving them
- std::list<motif> motif_list;
+ MotifListRef motif_list;
//! copy over all our annotation children
void copy_children(Sequence &, size_type start, size_type count) const;
#include <list>
#include <vector>
-#include "alg/annotation_colors.hpp"
-#include "alg/glseqbrowser.hpp"
-#include "alg/sequence.hpp"
+#include "annotation_colors.hpp"
+#include "glseqbrowser.hpp"
+#include "mussa.hpp"
+#include "sequence.hpp"
using namespace std;
Sequence seq0(s0);
Sequence seq1(s1);
Sequence seq2(s2);
-
+
GlSeqBrowser gt;
gt.push_sequence(seq0);
gt.push_sequence(seq1);
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(seq_locs.front().getSequence(), seq0);
BOOST_CHECK_EQUAL(seq_locs.front().getLeft(), 0);
BOOST_CHECK_EQUAL(seq_locs.front().getRight(), 2);
-
-}
+}
\ No newline at end of file
BOOST_CHECK_EQUAL(s->get_species(), "foo");
BOOST_CHECK_EQUAL(c->get_species(), "bar");
}
+
+BOOST_AUTO_TEST_CASE( sequence_copy_constructor_copy_motifs )
+{
+ SequenceRef s(new Sequence("AAAAGGGGAAAA"));
+ s->add_motif("AAGG");
+ BOOST_CHECK_EQUAL(s->motifs().size(), 1);
+
+ SequenceRef c(new Sequence(s->subseq()));
+ BOOST_CHECK_EQUAL(c->motifs().size(), 1);
+
+ s->clear_motifs();
+ BOOST_CHECK_EQUAL(s->motifs().size(), 0);
+ // FIXME: Technically c shouldn't lose its motifs.
+ // FIXME: getting that to work is hard.
+ // BOOST_CHECK_EQUAL(c->motifs().size(), 1);
+ BOOST_CHECK_EQUAL(c->motifs().size(), 0);
+}
+
BOOST_AUTO_TEST_CASE( sequence_get_sequence )
{
Sequence s;
QVERIFY(sequences2[0]->motifs().size() == 1);
QVERIFY(sequences2[1]->motifs().size() == 0);
QVERIFY(cm->lookup("motif", "AAGG") == Color(0.0, 1.0, 0.0));
+ QVERIFY(m->colorMapper()->lookup("motif", "AAGG") == Color(0.0, 1.0, 0.0));
+
+ QVERIFY(editor->get_analysis() == m);
+ QVERIFY(editor->get_model() == model);
+ QVERIFY(m->colorMapper() == cm);
+ }
+
+ void testEditMotifApply() {
+ std::vector<Sequence> motifs;
+ motifs.push_back("AAGG");
+ std::vector<Color> colors;
+ colors.push_back(Color(0.0, 0.0, 1.0));
+
+ MussaRef m(new Mussa);
+ m->append_sequence("AAAAGGGG");
+ m->append_sequence("AAAACCCC");
+ m->set_motifs(motifs, colors);
+
+ // do the sequences have the right motifs?
+ std::vector<SequenceRef> sequences1(m->sequences());
+ QVERIFY(sequences1[0]->get_sequence() == "AAAAGGGG");
+ QVERIFY(sequences1[1]->get_sequence() == "AAAACCCC");
+ QVERIFY(sequences1[0]->motifs().size() == 1);
+ QVERIFY(sequences1[1]->motifs().size() == 0);
+
+ // get color
+ boost::shared_ptr<AnnotationColors> cm(m->colorMapper());
+ QVERIFY(cm->lookup("motif", "AAGG") == Color(0.0, 0.0, 1.0));
+
+ MotifEditor *editor(new MotifEditor(m));
+ MotifModel *model(editor->get_model());
+ // the AATT motif and the empty motif
+ QVERIFY(model->size() == 2);
+ QModelIndex row0_color(model->index(0, MotifModel::ColorCell));
+ QModelIndex row0_sequence(model->index(0, MotifModel::SequenceCell));
+ QVERIFY(model->data(row0_sequence) == "AAGG");
+
+ // change contents of cell
+ model->setData(row0_sequence, QVariant("AACC"));
+ // this is equivalent to pressing apply
+ editor->updateAnalysisMotifs();
+ QVERIFY(model->data(row0_sequence) == "AACC");
+
+ // does the mussa analysis have the right data?
+ std::vector<SequenceRef> sequences2(m->sequences());
+ QVERIFY(sequences2[0]->motifs().size() == 0);
+ QVERIFY(sequences2[1]->motifs().size() == 1);
+ QVERIFY(cm->lookup("motif", "AACC") == Color(0.0, 0.0, 1.0));
+ QVERIFY(m->colorMapper()->lookup("motif", "AACC") == Color(0.0, 0.0, 1.0));
+ QVERIFY(cm->lookup("motif", "AAGG") == Color(0.0, 0.0, 0.0));
+ QVERIFY(m->colorMapper()->lookup("motif", "AAGG") == Color(0.0, 0.0, 0.0));
QVERIFY(editor->get_analysis() == m);
QVERIFY(editor->get_model() == model);
return QSize(width, center.height());
}
-
void SequenceBrowserWidget::clear()
{
converted_sequences.clear();
}
void SequenceBrowserWidget::setSequences(
- const std::vector<boost::shared_ptr<Sequence> >& sequences,
- boost::shared_ptr<AnnotationColors> cm)
+ const std::vector<SequenceRef >& new_sequences,
+ AnnotationColorsRef cm)
{
SequenceBrowser& browser = scrollable_browser->browser();
clear();
- for(Mussa::vector_sequence_type::const_iterator seq_i = sequences.begin();
- seq_i != sequences.end();
+ for(Mussa::vector_sequence_type::const_iterator seq_i = new_sequences.begin();
+ seq_i != new_sequences.end();
++seq_i)
{
// Blech *(*seq_i) is dereferencing the shared_ptr stored in the iterator.
- boost::shared_ptr<GlSequence> gs(new GlSequence(*(*seq_i), cm));
+ boost::shared_ptr<GlSequence> gs(new GlSequence(*seq_i, cm));
converted_sequences.push_back(gs);
browser.push_sequence(gs);
}
// connect the text change signals to each other
SequenceBrowserSidebar::collection left = left_sidebar->descriptions;
SequenceBrowserSidebar::collection right = right_sidebar->descriptions;
- for(size_t i = 0; i != sequences.size() and i != right.size(); ++i)
+ for(size_t i = 0; i != new_sequences.size() and i != right.size(); ++i)
{
connect(left[i], SIGNAL(nameChanged(const QString &)),
right[i], SLOT(setName(const QString &)));
public:
SequenceBrowserWidget(boost::shared_ptr<QDir>, QWidget *parent=0);
+ //! return our wrapped browser, so we can test it.
+ SequenceBrowser& browser() { return scrollable_browser->browser(); }
+
//! return the popup menu for the glcanvas (reference stored internally)
QMenu *getPopupMenu();
//! return our fasta copy action (reference stored internally)
//! sequences created by a setSequences(vector<Sequences>) call
/*! I need to save them so i can free them to avoid a memory leak
*/
- std::vector<boost::shared_ptr<GlSequence> > converted_sequences;
+ std::vector<GlSequenceRef > converted_sequences;
};
#endif
INCLUDE( TestMacros )
MAKE_QUI_UNITTEST(TestSequenceBrowser)
+MAKE_QUI_UNITTEST(TestSequenceBrowserWidget)
MAKE_QUI_UNITTEST(TestSequenceDescription)
\ No newline at end of file
--- /dev/null
+#include "TestSequenceBrowserWidget.hpp"
+
+QTEST_MAIN(TestSequenceBrowserWidget)
--- /dev/null
+#ifndef TESTSEQUENCEBROWSERWIDGET_HPP_
+#define TESTSEQUENCEBROWSERWIDGET_HPP_
+#include <QtGui>
+#include <QVariant>
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include "alg/sequence.hpp"
+#include "qui/seqbrowser/SequenceBrowserWidget.hpp"
+
+class TestSequenceBrowserWidget : public QObject
+{
+ Q_OBJECT
+
+private slots:
+
+ void testSimpleConstructor() {
+ boost::shared_ptr<QDir> d(new QDir("."));
+ SequenceBrowserWidget *browser = new SequenceBrowserWidget(d);
+ }
+
+ // do we have the right colors?
+ void testChangeMotifColor() {
+ boost::shared_ptr<QDir> d(new QDir("."));
+
+ std::vector<Sequence> motifs;
+ motifs.push_back("AAGG");
+ std::vector<Color> colors1;
+ colors1.push_back(Color(0.0, 0.0, 1.0));
+
+ MussaRef m(new Mussa);
+ m->append_sequence("AAAAGGGGTTTT");
+ m->set_motifs(motifs, colors1);
+ QVERIFY(m->sequences().size() == 1);
+ QVERIFY(m->sequences()[0]->motifs().size() == 1);
+ QVERIFY(m->sequences()[0]->motifs().front().sequence == "AAGG");
+ QVERIFY(m->colorMapper()->lookup("motif", "AAGG") == colors1[0]);
+
+ SequenceBrowserWidget *browser = new SequenceBrowserWidget(d);
+ browser->setSequences(m->sequences(), m->colorMapper());
+ std::vector<GlSequenceRef> glseqs1(browser->sequences());
+ QVERIFY(glseqs1.size() == 1);
+ QVERIFY(glseqs1[0]->colorMapper() == m->colorMapper());
+ QVERIFY(glseqs1[0]->colorMapper()->lookup("motif", "AAGG") == colors1[0]);
+
+ std::vector<Color> colors2;
+ colors2.push_back(Color(1.0, 0.0, 0.0));
+ m->set_motifs(motifs, colors2);
+ QVERIFY(m->sequences().size() == 1);
+ QVERIFY(m->sequences()[0]->motifs().size() == 1);
+ QVERIFY(m->sequences()[0]->motifs().front().sequence == "AAGG");
+ QVERIFY(m->colorMapper()->lookup("motif", "AAGG") == colors2[0]);
+
+ std::vector<GlSequenceRef> glseqs2(browser->sequences());
+ QVERIFY(glseqs2.size() == 1);
+ QVERIFY(glseqs2[0]->colorMapper() == m->colorMapper());
+ QVERIFY(glseqs2[0]->colorMapper()->lookup("motif", "AAGG") == colors2[0]);
+ }
+
+ // do we have the right colors?
+ void testChangeMotifSequencer() {
+ boost::shared_ptr<QDir> d(new QDir("."));
+
+ std::string aagg("AAGG");
+ std::vector<Sequence> motifs1;
+ motifs1.push_back(aagg);
+ std::vector<Color> colors1;
+ colors1.push_back(Color(0.0, 0.0, 1.0));
+
+ MussaRef m(new Mussa);
+ m->append_sequence("AAAAGGGG");
+ m->append_sequence("AAAACCCC");
+ m->set_motifs(motifs1, colors1);
+ QVERIFY(m->sequences().size() == 2);
+ QVERIFY(m->sequences()[0]->motifs().size() == 1);
+ QVERIFY(m->sequences()[0]->motifs().front().sequence == aagg);
+ QVERIFY(m->sequences()[1]->motifs().size() == 0);
+ QVERIFY(m->colorMapper()->lookup("motif", aagg) == colors1[0]);
+
+ SequenceBrowserWidget *browser = new SequenceBrowserWidget(d);
+ browser->setSequences(m->sequences(), m->colorMapper());
+ // does the sequence browser have the right motif pattern?
+ std::vector<GlSequenceRef> glseqs1(browser->sequences());
+ QVERIFY(glseqs1.size() == 2);
+ QVERIFY(glseqs1[0]->motifs().size() == 1);
+ QVERIFY(glseqs1[0]->motifs().front().sequence == aagg);
+ QVERIFY(glseqs1[1]->motifs().size() == 0);
+ QVERIFY(glseqs1[0]->colorMapper() == m->colorMapper());
+ QVERIFY(glseqs1[0]->colorMapper()->lookup("motif", aagg) == colors1[0]);
+
+ std::vector<Sequence> motifs2;
+ std::string aacc("AACC");
+ motifs2.push_back(aacc);
+ m->set_motifs(motifs2, colors1);
+ // did the copy of our sequences in the mussa analysis object get updated?
+ QVERIFY(m->sequences().size() == 2);
+ QVERIFY(m->sequences()[0]->motifs().size() == 0);
+ QVERIFY(m->sequences()[1]->motifs().size() == 1);
+ QVERIFY(m->sequences()[1]->motifs().front().sequence == aacc);
+ QVERIFY(m->colorMapper()->lookup("motif", aacc) == colors1[0]);
+
+ // did the copy of our sequences in the browser get updated?
+ std::vector<GlSequenceRef> glseqs2(browser->sequences());
+ QVERIFY(glseqs2.size() == 2);
+ QVERIFY(glseqs2[0]->motifs().size() == 0);
+ QVERIFY(glseqs2[1]->motifs().size() == 1);
+ QVERIFY(glseqs2[1]->motifs().front().sequence == aacc);
+ QVERIFY(glseqs2[0]->colorMapper() == m->colorMapper());
+ QVERIFY(glseqs2[0]->colorMapper()->lookup("motif", aacc) == colors1[0]);
+ }
+};
+#endif /*TESTSEQUENCEBROWSERWIDGET_HPP_*/