Update mussa to build on ubuntu 10.04 with qt 4.6.2 +boost 1.40.0.1
[mussa.git] / qui / MussaAlignedWindow.cpp
index e4c058ef7bf99a8fb3ad7dcbaf3b281fa985324b..7e4246dfb79509db70a90d15dd275605d9e4646e 100644 (file)
 #include <iostream>
 using namespace std;
 
-MussaAlignedWindow::MussaAlignedWindow(Mussa& m, 
-                                       const set<int>& sel_paths, 
+MussaAlignedWindow::MussaAlignedWindow(MussaRef m,
+                                       boost::shared_ptr<QDir> default_dir_,
+                                       const set<int>& sel_paths,
+                                       SubanalysisWindowRef window, 
                                        QWidget *parent)
   : QMainWindow(parent),
     analysis(m),
+    default_dir(default_dir_),
+    subanalysis_window(window),
+    browser(default_dir),
     pick_align_menu(tr("Choose Alignment")),
-    view_align_menu(tr("View Alignment"))
+    view_align_menu(tr("View Alignment")),
+    threshold_widget(0),
+    zoom(0),
+    alignTB(0)
 {
-  browser.setSequences(analysis.sequences(), analysis.colorMapper());
-  setSelectedPaths(m, sel_paths);
+  setupActions();
+  connect(&browser, SIGNAL(basepairsCopied(size_t)), 
+          this, SLOT(showBasePairsCopied(size_t)));
+  browser.setSequences(analysis->sequences(), analysis->colorMapper());
+  setSelectedPaths(analysis, sel_paths);
   setAlignment(0);
   double zoom_level = browser.zoomToSequence();
-  zoom.setValue(zoom_level);
+
+  zoom = new ZoomWidget();
+  connect(zoom, SIGNAL(valueChanged(double)), 
+          &browser, SLOT(setZoom(double)));
+  zoom->setValue(zoom_level);
+  
+  // Mouse scroll wheel zooming!
+  connect(&browser, SIGNAL(mouseWheelZoom(double)),
+                 zoom, SLOT(setValue(double)));
+  
   computeMatchLines();
   setupMenus();
-
-  addToolBar(&alignTB);
-  alignTB.addWidget(&zoom);
+  setupAlignmentMenus();
   
-  connect(&zoom, SIGNAL(valueChanged(double)), 
-          &browser, SLOT(setZoom(double)));
   setCentralWidget(&browser);
-  menuBar()->addMenu(&pick_align_menu);
-  menuBar()->addMenu(&view_align_menu);
 
+  // Add a threhold widget set to our current threshold and make it readonly 
+  threshold_widget = new ThresholdWidget;
+  threshold_widget->setRange(analysis->get_threshold(),analysis->get_window());
+  threshold_widget->setBasepairThreshold(analysis->get_soft_threshold());
+  threshold_widget->setReadOnly(true);
+  
+  alignTB = new QToolBar();
+  alignTB->addWidget(zoom);
+  alignTB->addWidget(threshold_widget);
+  addToolBar(alignTB);
+  
   ostringstream message;
   message << "Selected " << selected_paths.size() << " paths";
   statusBar()->showMessage(message.str().c_str(), 5000);
   browser.updatePosition();
+  
+  updateTitle();
 }
 
+void MussaAlignedWindow::setupActions()
+{
+  // more cut-n-paste from MussaWindow
+  createSubAnalysisAction = new QAction(tr("Add to Subanalysis"), this);
+  connect(createSubAnalysisAction, SIGNAL(triggered()), 
+          this, SLOT(createSubAnalysis()));
+            
+  //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"));
+}
 
-void MussaAlignedWindow::setSelectedPaths(Mussa &m, const set<int>& sel_paths)
+void MussaAlignedWindow::setupMenus()
 {
-  // sets are sorted
-  set<int>::iterator sel_i = sel_paths.begin();
-  list<ExtendedConservedPath>::const_iterator path_i = m.paths().rpbegin();
-  list<ExtendedConservedPath>::const_iterator path_end = m.paths().rpend();
-  size_t path_size = m.paths().refined_pathz.size();
-  size_t pathid=0;
+  QMenu *newMenu = menuBar()->addMenu(tr("&File"));
+  newMenu->addAction(saveBrowserPixmapAction);
 
-  selected_paths.reserve(sel_paths.size());
-  view_paths.reserve(sel_paths.size());
-  while (pathid != path_size and sel_i != sel_paths.end())
-  {
-    assert (*sel_i >= 0);
-    size_t sel_pathid = (size_t)(*sel_i);
-    if (pathid == sel_pathid) {
-      selected_paths.push_back(*path_i);
-      view_paths.push_back(true);
-      ++pathid;
-      ++path_i;
-      ++sel_i;
-    } else if (pathid < sel_pathid) {
-      ++pathid;
-      ++path_i;
-    } else if (pathid > sel_pathid) {
-      ++sel_i;
-    }
-  }
+  newMenu = menuBar()->addMenu(tr("&Edit"));
+  newMenu->addAction(browser.getCopySelectedSequenceAsStringAction());
+  newMenu->addAction(browser.getCopySelectedSequenceAsFastaAction());
+  newMenu->addAction(createSubAnalysisAction);
+  
+  // add some extra features to the context menu
+  QMenu *popupMenu = browser.getPopupMenu();
+  if (popupMenu) {
+    popupMenu->addAction(createSubAnalysisAction);
+  }  
 }
 
-void MussaAlignedWindow::setupMenus()
+void MussaAlignedWindow::setupAlignmentMenus()
 {
   pick_align_menu.clear();
   view_align_menu.clear();
   pick_actions.clear();
   view_actions.clear();
 
-  for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
+  for(vector<ConservedPath >::iterator pathz_i=selected_paths.begin(); 
       pathz_i != selected_paths.end(); 
       ++pathz_i)
   {
@@ -110,6 +136,59 @@ void MussaAlignedWindow::setupMenus()
     view_actions.push_back(view);
     view_align_menu.addAction(view);
   }
+
+  menuBar()->addMenu(&pick_align_menu);
+  menuBar()->addMenu(&view_align_menu);
+}
+
+
+void MussaAlignedWindow::setSelectedPaths(MussaRef m, const set<int>& sel_paths)
+{
+  // sets are sorted
+  set<int>::iterator sel_i = sel_paths.begin();
+  list<ConservedPath>::const_iterator path_i = m->paths().refined_pathz.begin();
+  list<ConservedPath>::const_iterator path_end = m->paths().refined_pathz.end();
+  size_t path_size = m->paths().refined_pathz.size();
+  size_t pathid=0;
+
+  selected_paths.reserve(sel_paths.size());
+  view_paths.reserve(sel_paths.size());
+  while (pathid != path_size and sel_i != sel_paths.end())
+  {
+    assert (*sel_i >= 0);
+    size_t sel_pathid = (size_t)(*sel_i);
+    if (pathid == sel_pathid) {
+      selected_paths.push_back(*path_i);
+      view_paths.push_back(true);
+      ++pathid;
+      ++path_i;
+      ++sel_i;
+    } else if (pathid < sel_pathid) {
+      ++pathid;
+      ++path_i;
+    } else if (pathid > sel_pathid) {
+      ++sel_i;
+    }
+  }
+}
+
+// FIXME: this is a cut-n-paste from MussaWindow, perhaps they should be refactored to
+// some shared place
+void MussaAlignedWindow::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();
+  }
 }
 
 void MussaAlignedWindow::setAlignment(int alignment_index)
@@ -119,6 +198,15 @@ void MussaAlignedWindow::setAlignment(int alignment_index)
   }
 }
 
+void MussaAlignedWindow::showBasePairsCopied(size_t bp_copied)
+{
+  QString msg("Copied ");
+  QString num;
+  num.setNum(bp_copied);
+  msg += num + " base pairs";
+  statusBar()->showMessage(msg, 5000);
+}
+
 void MussaAlignedWindow::toggleViewAlignment(int alignment_index)
 {
   view_paths[alignment_index]= not view_paths[alignment_index]; 
@@ -133,112 +221,42 @@ void MussaAlignedWindow::update()
   browser.update();
 }
 
-void MussaAlignedWindow::computeMatchLines()
+void MussaAlignedWindow::updateTitle()
 {
-  const vector<Sequence>& raw_seq = analysis.sequences();
-  vector<int> aligned_path;
-  size_t i2, i3;
-  int x_start, x_end;
-  int window_length, win_i;
-  int rc_1 = 0; 
-  int rc_2 = 0;
-  vector<bool> rc_list;
-  bool full_match;
-  vector<bool> matched;
-  int align_counter;
+  std::string title("Sequence View: ");
+  if (analysis) {
+    title += analysis->get_title();
+  }
+  setWindowTitle(title.c_str());
+}
 
+void MussaAlignedWindow::computeMatchLines()
+{
   browser.clear_links();
-  align_counter = 0;
-  for(vector<ExtendedConservedPath >::iterator pathz_i=selected_paths.begin(); 
-      pathz_i != selected_paths.end(); 
-      ++pathz_i)
+  
+  // filter out conserved paths
+  list<ConservedPath> filtered_paths;
+  vector<ConservedPath>::iterator path_i = selected_paths.begin();
+  list<ConservedPath::path_type> result;
+  list<vector<bool> > reversed;
+
+  for(vector<ConservedPath>::size_type count = 0; 
+      count != selected_paths.size();
+      ++count, ++path_i)
   {
-    if (view_paths[align_counter])
-    {
-      ExtendedConservedPath& a_path = *pathz_i;
-      window_length = a_path.window_size;
-      // determine which parts of the path are RC relative to first species
-      rc_list = a_path.reverseComplimented();
-      
-      // loop over each bp in the conserved region for all sequences
-      for(win_i = 0; win_i < window_length; win_i++)
-      {
-        aligned_path.clear();
-        // determine which exact base pairs match between the sequences
-        full_match = true;
-        for(i2 = 0; i2 < a_path.size()-1; i2++)
-        {
-          // assume not rc as most likely, adjust below
-          rc_1 = 0;
-          rc_2 = 0;
-          // no matter the case, any RC node needs adjustments
-          if (a_path[i2] < 0)
-            rc_1 = window_length-1;
-          if (a_path[i2+1] < 0)
-            rc_2 = window_length-1;        
-           
-          x_start = (abs(a_path[i2]-rc_1+win_i));
-          x_end =   (abs(a_path[i2+1]-rc_2+win_i));
-          
-          // RC case handling
-          // ugh, and xor...only want rc coloring if just one of the nodes is rc
-          // if both nodes are rc, then they are 'normal' relative to each other
-          if((rc_list[i2] || rc_list[i2+1] )&&!(rc_list[i2] && rc_list[i2+1]))
-          { //the hideous rc matching logic - not complex, but annoying
-            if(!(( (raw_seq[i2][x_start]=='A')&&(raw_seq[i2+1][x_end]=='T')) ||
-                  ((raw_seq[i2][x_start]=='T')&&(raw_seq[i2+1][x_end]=='A')) ||
-                  ((raw_seq[i2][x_start]=='G')&&(raw_seq[i2+1][x_end]=='C')) ||
-                  ((raw_seq[i2][x_start]=='C')&&(raw_seq[i2+1][x_end]=='G'))) )
-              full_match = false;
-          }
-          else
-          {
-            if (!( (raw_seq[i2][x_start] == raw_seq[i2+1][x_end]) &&
-                  (raw_seq[i2][x_start] != 'N') &&
-                  (raw_seq[i2+1][x_end] != 'N') ) )
-              full_match = false;
-          }
-        }
-        
-        // draw for matches stretching across all sequences
-        if (full_match)
-        {
-          // now can draw the line for each bp in this window that matches
-          // grrr, need to ask if anyone cares if I switch the seq 
-          // top-bot order...
-          i3 = 0;
-          //y_loc = y_min + 5;
-          for(i2 = 0; i2 < a_path.size()-1; i2++)
-          {
-            // assume not rc as most likely, adjust below
-            rc_1 = 0;
-            rc_2 = 0;
-            // no matter the case, any RC node needs adjustments
-            if (a_path[i2] < 0)
-            {
-              rc_1 = window_length;        
-            }
-            if (a_path[i2] < 0)
-            {
-              rc_2 = window_length;        
-            }
-            
-            // maybe shouldn't recalc these, but store values from first loop
-            x_start = (abs((int) (a_path[i2]-rc_1+win_i)));
-            x_end =   (abs((int) (a_path[i2+1]-rc_2+win_i)));
-            aligned_path.push_back(x_start);
-            // if we're on the last time through the loop, save x_end too
-            if (i2 == a_path.size()-2) {
-              aligned_path.push_back(x_end);
-            }
-          }
-        }
-        if (aligned_path.size() > 0) {
-          browser.link(aligned_path, rc_list,1);
-        }
-      }
-    }
-    align_counter++;
+    if (view_paths[count]) 
+      filtered_paths.push_back(*path_i);
   }
-}
+  analysis->createLocalAlignment(filtered_paths.begin(), 
+                                 filtered_paths.end(),
+                                 result, 
+                                 reversed);
 
+  list<ConservedPath::path_type>::const_iterator result_i = result.begin();
+  list<vector<bool> >::const_iterator reversed_i = reversed.begin();
+  for(int i = 0; i != result.size(); ++i, ++result_i, ++reversed_i)
+  {
+    // make 1 base long links
+    browser.link(*result_i, *reversed_i, 1);
+  }
+}