From ba26165951a034fec35c81719544d5bef562af05 Mon Sep 17 00:00:00 2001
From: stefan <stefan@5a81b35b-ba03-0410-adc8-b2c5c5119f08>
Date: Mon, 3 May 2010 10:53:10 +0000
Subject: [PATCH] New sequence viewer, added secondary structure rendering

git-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@2163 5a81b35b-ba03-0410-adc8-b2c5c5119f08
---
 modules/gui/src/CMakeLists.txt                |  3 +
 .../gui/src/sequence/seq_secstr_painter.cc    | 99 +++++++++++++++++++
 .../gui/src/sequence/seq_secstr_painter.hh    | 43 ++++++++
 modules/gui/src/sequence/seq_text_painter.cc  |  4 +-
 modules/gui/src/sequence/sequence_model.cc    | 12 +++
 modules/gui/src/sequence/sequence_model.hh    |  3 +
 modules/gui/src/sequence/sequence_viewer.cc   | 16 +--
 modules/gui/src/sequence/view_object.cc       | 76 +++++++++++---
 modules/gui/src/sequence/view_object.hh       | 30 +++++-
 9 files changed, 257 insertions(+), 29 deletions(-)
 create mode 100644 modules/gui/src/sequence/seq_secstr_painter.cc
 create mode 100644 modules/gui/src/sequence/seq_secstr_painter.hh

diff --git a/modules/gui/src/CMakeLists.txt b/modules/gui/src/CMakeLists.txt
index 01ed36015..4bba75bb2 100644
--- a/modules/gui/src/CMakeLists.txt
+++ b/modules/gui/src/CMakeLists.txt
@@ -23,6 +23,7 @@ sequence_search_bar.hh
 set(OST_GUI_SEQUENCE_VIEW_HEADERS
 painter.hh
 row.hh
+seq_secstr_painter.hh
 seq_selection_painter.hh
 seq_text_painter.hh
 sequence_delegate.hh
@@ -206,6 +207,7 @@ sequence_viewer/sequence_viewer.cc
 sequence_viewer/sequence_scene.cc
 sequence_viewer/sequence_search_bar.cc
 sequence/row.cc
+sequence/seq_secstr_painter.cc
 sequence/seq_selection_painter.cc
 sequence/seq_text_painter.cc
 sequence/sequence_delegate.cc
@@ -331,6 +333,7 @@ sequence_viewer/sequence_scene.hh
 sequence_viewer/sequence_search_bar.hh
 sequence/painter.hh
 sequence/row.hh
+sequence/seq_secstr_painter.hh
 sequence/seq_selection_painter.hh
 sequence/seq_text_painter.hh
 sequence/sequence_delegate.hh
diff --git a/modules/gui/src/sequence/seq_secstr_painter.cc b/modules/gui/src/sequence/seq_secstr_painter.cc
new file mode 100644
index 000000000..095841b25
--- /dev/null
+++ b/modules/gui/src/sequence/seq_secstr_painter.cc
@@ -0,0 +1,99 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Stefan Scheuber
+ */
+
+
+#include <QtGui>
+
+#include "seq_secstr_painter.hh"
+#include "view_object.hh"
+
+namespace ost { namespace gui {
+
+SeqSecStrPainter::SeqSecStrPainter(QObject* parent)
+    : Painter(parent)
+{}
+
+void SeqSecStrPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index){
+  QVariant var = index.data(Qt::UserRole);
+  painter->save();
+  painter->setPen(QPen(Qt::lightGray));
+  ListEntry entry = index.data(Qt::UserRole).value<ListEntry>();
+  if(entry.secstr.size()>0){
+    QSize size = index.data(Qt::UserRole+1).toSize();
+    QVarLengthArray<mol::SecStructure>& sec_str = entry.secstr;
+    int column = index.column()-1;
+    if(column < sec_str.size()){
+      mol::SecStructure sec_element = sec_str[column];
+
+      int std_diff = (size.height()/2);
+      int diff = size.height()/1.25;
+      int center = option.rect.top()+(option.rect.height()/2);
+
+      if (sec_element.IsCoil()) {
+        int pos = center - std_diff;
+        painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+        pos = center + std_diff;
+        painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+        //stack.push_back(QPointF(s.first*advance_, -.6*height_));
+        //stack.push_back(QPointF((s.last+1)*advance_,  -.6*height_));
+      } else if (sec_element.IsHelical()) {
+        int pos = center - diff;
+        painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+        pos = center + diff;
+        painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+        if(column - 1 > 0 && !sec_str[column-1].IsHelical()){
+          painter->drawLine(option.rect.left(),center+std_diff,option.rect.left(),center+diff);
+          painter->drawLine(option.rect.left(),center-std_diff,option.rect.left(),center-diff);
+        }
+        if(column + 1 < sec_str.size() && !sec_str[column+1].IsHelical()){
+          painter->drawLine(option.rect.right(),center+std_diff,option.rect.right(),center+diff);
+          painter->drawLine(option.rect.right(),center-std_diff,option.rect.right(),center-diff);
+        }
+      } else if (sec_element.IsExtended()) {
+        int pos = center - diff;
+        if(column - 1 > 0 && !sec_str[column-1].IsExtended()){
+          painter->drawLine(option.rect.left(),center+std_diff,option.rect.left(),center+diff);
+          painter->drawLine(option.rect.left(),center-std_diff,option.rect.left(),center-diff);
+        }
+        if(column + 1 < sec_str.size() && !sec_str[column+1].IsExtended()){
+          int max_diff = size.height();
+          painter->drawLine(option.rect.left(),center+diff,option.rect.left(),center+max_diff);
+          painter->drawLine(option.rect.left(),center-diff,option.rect.left(),center-max_diff);
+          painter->drawLine(option.rect.left(),center+max_diff,option.rect.right(),center+std_diff);
+          painter->drawLine(option.rect.left(),center-max_diff,option.rect.right(),center-std_diff);
+        }
+        else{
+          painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+          pos = center + diff;
+          painter->drawLine(option.rect.left(),pos,option.rect.right(),pos);
+        }
+      }
+      if(!(column+1 < sec_str.size())){
+        painter->drawLine(option.rect.right(),center+std_diff,option.rect.right(),center-std_diff);
+      }
+    }
+  }
+  painter->restore();
+}
+
+}}
diff --git a/modules/gui/src/sequence/seq_secstr_painter.hh b/modules/gui/src/sequence/seq_secstr_painter.hh
new file mode 100644
index 000000000..7255a5f3e
--- /dev/null
+++ b/modules/gui/src/sequence/seq_secstr_painter.hh
@@ -0,0 +1,43 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_SEQUENCE_VIEWER_SEQ_SECSTR_PAINTER
+#define OST_SEQUENCE_VIEWER_SEQ_SECSTR_PAINTER
+
+/*
+  Author: Stefan Scheuber
+ */
+
+#include <QObject>
+
+#include "painter.hh"
+
+namespace ost { namespace gui {
+
+class SeqSecStrPainter : public Painter
+{
+  Q_OBJECT
+public:
+  SeqSecStrPainter(QObject* parent = 0);
+  void Paint(QPainter *painter, const QStyleOptionViewItem &option,
+      const QModelIndex &index);
+};
+
+}}
+
+#endif
diff --git a/modules/gui/src/sequence/seq_text_painter.cc b/modules/gui/src/sequence/seq_text_painter.cc
index 9ac48a688..30c1e1623 100644
--- a/modules/gui/src/sequence/seq_text_painter.cc
+++ b/modules/gui/src/sequence/seq_text_painter.cc
@@ -38,8 +38,8 @@ void SeqTextPainter::Paint(QPainter* painter, const QStyleOptionViewItem& option
   QVariant value = index.data(Qt::DisplayRole);
   if (value.isValid()){
     QString text = value.toString();
-    painter->setFont(QFont("Courier",10));
-    painter->drawText(option.rect, Qt::AlignLeft|Qt::AlignVCenter, text);
+    painter->setFont(index.data(Qt::FontRole).value<QFont>());
+    painter->drawText(option.rect, Qt::AlignCenter, text);
   }
   painter->restore();
 }
diff --git a/modules/gui/src/sequence/sequence_model.cc b/modules/gui/src/sequence/sequence_model.cc
index 06199fbf4..f52ddfd60 100644
--- a/modules/gui/src/sequence/sequence_model.cc
+++ b/modules/gui/src/sequence/sequence_model.cc
@@ -45,6 +45,18 @@ void SequenceModel::InsertSequence(QString& name, seq::SequenceHandle& seq){
   this->endInsertRows();
 }
 
+void SequenceModel::InsertChain(QString& name, mol::ChainView& view){
+  int cols = this->columnCount();
+  int new_cols = view.GetResidueCount();
+  this->beginInsertRows(QModelIndex(),this->rowCount(),this->rowCount());
+  objects_.append(new ViewObject(view, name, this));
+  if(new_cols > cols){
+    this->beginInsertColumns(QModelIndex(), cols, new_cols);
+    this->endInsertColumns();
+  }
+  this->endInsertRows();
+}
+
 void SequenceModel::InsertSequences(QString& name, seq::SequenceList& list){
   this->beginInsertRows(this->index(this->rowCount(),0),this->rowCount(),this->rowCount()+list.GetCount());
   objects_.append(new ViewObject(list, name, this));
diff --git a/modules/gui/src/sequence/sequence_model.hh b/modules/gui/src/sequence/sequence_model.hh
index 234cebc7b..2b7bc481b 100644
--- a/modules/gui/src/sequence/sequence_model.hh
+++ b/modules/gui/src/sequence/sequence_model.hh
@@ -25,6 +25,8 @@
 
 #include <QAbstractTableModel>
 
+#include <ost/mol/chain_view.hh>
+
 #include <ost/seq/sequence_list.hh>
 
 #include "sequence_model.hh"
@@ -39,6 +41,7 @@ class SequenceModel : public QAbstractTableModel
 public:
   SequenceModel(QObject *parent = 0);
 
+  void InsertChain(QString& name, mol::ChainView& view);
   void InsertSequence(QString& name, seq::SequenceHandle& seq);
   void InsertSequences(QString& name, seq::SequenceList& list);
 
diff --git a/modules/gui/src/sequence/sequence_viewer.cc b/modules/gui/src/sequence/sequence_viewer.cc
index 4fa20eac3..25fbcfee1 100644
--- a/modules/gui/src/sequence/sequence_viewer.cc
+++ b/modules/gui/src/sequence/sequence_viewer.cc
@@ -67,25 +67,11 @@ void SequenceViewerV2::NodeAdded(const gfx::GfxNodeP& n)
     for (mol::ChainViewList::const_iterator c=v.GetChainList().begin(),
          e1=v.GetChainList().end(); c!=e1; ++c) {
       mol::ChainView chain=*c;
-      String seq_str;
-      seq_str.reserve(chain.GetResidueCount());
-      for (mol::ResidueViewList::const_iterator r=chain.GetResidueList().begin(),
-           e2=chain.GetResidueList().end(); r!=e2; ++r) {
-        mol::ResidueView res=*r;
-        seq_str.append(1, res.GetOneLetterCode());
-      }
-      if (seq_str.empty()) {
-        continue;
-      }
       QString name = QString(o->GetName().c_str());
       if (chain.GetName()!="" && chain.GetName()!=" ") {
         name= name + " ("+chain.GetName().c_str()+")";
       }
-      seq::SequenceHandle sequence=seq::CreateSequence(name.toStdString(), seq_str);
-      mol::EntityView v_one_chain=v.GetHandle().CreateEmptyView();
-      v_one_chain.AddChain(chain, mol::ViewAddFlag::INCLUDE_ALL);
-      sequence.AttachView(v_one_chain);
-      model_->InsertSequence(name,sequence);
+      model_->InsertChain(name,chain);
     }
     seq_table_view_->resizeColumnsToContents();
     seq_table_view_->resizeRowsToContents();
diff --git a/modules/gui/src/sequence/view_object.cc b/modules/gui/src/sequence/view_object.cc
index 43d6601e0..ce504fd8f 100644
--- a/modules/gui/src/sequence/view_object.cc
+++ b/modules/gui/src/sequence/view_object.cc
@@ -24,9 +24,12 @@
 
 #include <QtGui>
 
+#include <ost/mol/mol.hh>
+
 #include "painter.hh"
-#include "seq_text_painter.hh"
+#include "seq_secstr_painter.hh"
 #include "seq_selection_painter.hh"
+#include "seq_text_painter.hh"
 
 #include "view_object.hh"
 
@@ -47,19 +50,25 @@ ViewObject::ViewObject(seq::SequenceHandle& sequence, const QString& name, QObje
   this->Init();
 }
 
+ViewObject::ViewObject(mol::ChainView& chain, const QString& name, QObject *parent): QObject(parent), name_(name)
+{
+  this->AddChain(chain);
+  this->Init();
+}
+
 void ViewObject::Init()
 {
   font_ = QFont("Courier",10);
   QFontMetrics metrics = QFontMetrics(font_);
-  default_size_ = QSize(metrics.width(QString("_"))+2,metrics.height()+2);
+  default_size_=QSize(metrics.boundingRect('W').width(),metrics.boundingRect('|').height());
+  default_cell_size_ = QSize(metrics.boundingRect('W').width()+2,metrics.boundingRect('|').height()+2);
 }
 
 void ViewObject::InsertRow(int pos, Row* row)
 {
   if(pos >= 0 && pos <= rows_.size()){
-    seq::SequenceHandle sequence = seq::SequenceHandle();
-    QPair<Row*, seq::SequenceHandle> pair(row,sequence);
-    rows_.insert(pos,pair);
+    ListEntry entry(row);
+    rows_.insert(pos,entry);
   }
 }
 
@@ -67,7 +76,7 @@ void ViewObject::RemoveRow(Row* row)
 {
   QList<int> rows_to_delete;
   for (int i = 0; i < rows_.size(); ++i){
-    if(rows_[i].first == row){
+    if(rows_[i].row == row){
       rows_to_delete.append(i);
     }
   }
@@ -79,7 +88,7 @@ void ViewObject::RemoveRow(Row* row)
 Row* ViewObject::GetRow(int pos)
 {
    if(pos >= 0 && pos < rows_.size()){
-     return rows_[pos].first;
+     return rows_[pos].row;
    }
    return NULL;
 }
@@ -97,7 +106,44 @@ void ViewObject::AddSequence(seq::SequenceHandle& sequence)
   p = new SeqTextPainter(this);
   new_row->InsertPainter(p);
   QPair<Row*, seq::SequenceHandle> pair(new_row,sequence);
-  rows_.append(pair);
+  //rows_.append(pair);
+}
+
+void ViewObject::AddChain(mol::ChainView& chain)
+{
+  String seq_str;
+  seq_str.reserve(chain.GetResidueCount());
+  for (mol::ResidueViewList::const_iterator r=chain.GetResidueList().begin(),
+       e2=chain.GetResidueList().end(); r!=e2; ++r) {
+    mol::ResidueView res=*r;
+    seq_str.append(1, res.GetOneLetterCode());
+  }
+  if (!seq_str.empty()) {
+    seq::SequenceHandle sequence=seq::CreateSequence(this->GetName().toStdString(), seq_str);
+    mol::EntityView v_one_chain=chain.GetEntity().GetHandle().CreateEmptyView();
+    v_one_chain.AddChain(chain, mol::ViewAddFlag::INCLUDE_ALL);
+    sequence.AttachView(v_one_chain);
+
+    Row* new_row = new Row(this);
+    Painter* p = new SeqSelectionPainter(this);
+    new_row->InsertPainter(p);
+    p = new SeqSecStrPainter(this);
+    new_row->InsertPainter(p);
+    p = new SeqTextPainter(this);
+    new_row->InsertPainter(p);
+    QPair<Row*, seq::SequenceHandle> pair(new_row,sequence);
+    mol::alg::SecStructureSegments sec = mol::alg::ExtractSecStructureSegments(chain);
+    QVarLengthArray<mol::SecStructure> sec_str(chain.GetResidueCount());
+    for (mol::alg::SecStructureSegments::iterator i=sec.begin(),
+         e=sec.end(); i!=e; ++i) {
+      mol::alg::SecStructureSegment s=*i;
+      for(int i = s.first; i <= s.last ;i++){
+        sec_str[i] = s.ss_type;
+      }
+    }
+    ListEntry entry(new_row, sequence, sec_str);
+    rows_.append(entry);
+  }
 }
 
 QVariant ViewObject::GetData(int row, int column, int role)
@@ -113,12 +159,20 @@ QVariant ViewObject::GetData(int row, int column, int role)
   }
   else if(column > 0) {
     if (role==Qt::DisplayRole) {
-      return QVariant(QString(rows_[row].second.GetOneLetterCode(column - 1)));
+      return QVariant(QString(rows_[row].seq.GetOneLetterCode(column - 1)));
     }
     if (role==Qt::FontRole){
       return QVariant(font_);
     }
     if (role==Qt::SizeHintRole){
+      return QVariant(default_cell_size_);
+    }
+    if (role==Qt::UserRole){
+      QVariant variant;
+      variant.setValue(rows_[row]);
+      return variant;
+    }
+    if (role==Qt::UserRole+1){
       return QVariant(default_size_);
     }
   }
@@ -129,9 +183,9 @@ int ViewObject::GetMaxColumnCount() const
 {
   int columns = 0;
   for(int i = 0; i < rows_.size(); i++){
-    int col_length = rows_[i].second.GetLength();
+    int col_length = rows_[i].seq.GetLength();
     if(columns < col_length){
-      columns = rows_[i].second.GetLength() + 1;
+      columns = rows_[i].seq.GetLength() + 1;
     }
   }
   return columns;
diff --git a/modules/gui/src/sequence/view_object.hh b/modules/gui/src/sequence/view_object.hh
index d8ae32802..795d996cd 100644
--- a/modules/gui/src/sequence/view_object.hh
+++ b/modules/gui/src/sequence/view_object.hh
@@ -26,9 +26,13 @@
 #include <QObject>
 #include <QPair>
 #include <QList>
+#include <QVarLengthArray>
 #include <QFont>
 #include <QSize>
 
+#include <ost/mol/alg/sec_structure_segments.hh>
+#include <ost/mol/entity_handle.hh>
+
 #include <ost/seq/sequence_list.hh>
 
 #include "row.hh"
@@ -36,13 +40,33 @@
 
 namespace ost { namespace gui {
 
+struct ListEntry {
+  Row*   row;
+  seq::SequenceHandle seq;
+  QVarLengthArray<mol::SecStructure> secstr;
+  ListEntry(): row(NULL)
+         {}
+  ListEntry(Row* r): row(r)
+         {}
+  ListEntry(Row* r,
+      seq::SequenceHandle& sequence): row(r), seq(sequence)
+         {}
+  ListEntry(Row* r,
+      seq::SequenceHandle& sequence,
+      QVarLengthArray<mol::SecStructure>& sec): row(r), seq(sequence), secstr(sec)
+         {}
+};
+
+
 class ViewObject : public QObject
 {
   Q_OBJECT
 
+
 public:
   ViewObject(seq::SequenceList& sequences, const QString& name, QObject* parent = 0);
   ViewObject(seq::SequenceHandle& sequence, const QString& name, QObject* parent = 0);
+  ViewObject(mol::ChainView& chain, const QString& name, QObject* parent = 0);
 
   void InsertRow(int pos, Row* row);
   void RemoveRow(Row* row);
@@ -55,6 +79,7 @@ public:
   int GetMaxColumnCount() const;
 
   void AddSequence(seq::SequenceHandle& sequence);
+  void AddChain(mol::ChainView& chain);
 
   QVariant GetData(int row, int column, int role);
 
@@ -66,12 +91,15 @@ public:
 private:
   void Init();
   QString name_;
-  QList<QPair<Row*, seq::SequenceHandle> > rows_;
+  QList<ListEntry> rows_;
   QFont font_;
   QSize default_size_;
+  QSize default_cell_size_;
 };
 
 
 }}
 
+Q_DECLARE_METATYPE(ost::gui::ListEntry)
+
 #endif
-- 
GitLab