Browse Source

Add depth in the propagation of ctkCheckableHeaderView

ctkDICOMModel in ctkDICOMQueryRetrieveWidget now has a checkability depth
of 2 levels.
Julien Finet 14 years ago
parent
commit
b0ca0669bc

+ 55 - 12
Libs/DICOM/Core/ctkDICOMModel.cpp

@@ -77,6 +77,7 @@ public:
 
 //------------------------------------------------------------------------------
 // 1 node per row
+// TBD: should probably use the QStandardItems instead.
 struct Node
 {
   ~Node()
@@ -88,14 +89,15 @@ struct Node
     this->Children.clear();
     }
   ctkDICOMModelPrivate::IndexType Type;
-  Node*     Parent;
-  QVector<Node*> Children;
-  int       Row;
-  QSqlQuery Query;
-  QString   UID;
-  int       RowCount;
-  bool      AtEnd;
-  bool      Fetching;
+  Node*                           Parent;
+  QVector<Node*>                  Children;
+  int                             Row;
+  QSqlQuery                       Query;
+  QString                         UID;
+  int                             RowCount;
+  bool                            AtEnd;
+  bool                            Fetching;
+  QMap<int, QVariant>             Data;
 };
 
 //------------------------------------------------------------------------------
@@ -413,9 +415,19 @@ int ctkDICOMModel::columnCount ( const QModelIndex & _parent ) const
 QVariant ctkDICOMModel::data ( const QModelIndex & dataIndex, int role ) const
 {
   Q_D(const ctkDICOMModel);
-  if (role != Qt::DisplayRole && role != Qt::EditRole)
+  if (role != Qt::DisplayRole &&
+      role != Qt::EditRole)
     {
-    return QVariant();
+    if (dataIndex.column() != 0)
+      {
+      return QVariant();
+      }
+    Node* node = d->nodeFromIndex(dataIndex);
+    if (!node)
+      {
+      return QVariant();
+      }
+    return node->Data[role];
     }
   QModelIndex parentIndex = this->parent(dataIndex);
   Node* parentNode = d->nodeFromIndex(parentIndex);
@@ -446,8 +458,21 @@ void ctkDICOMModel::fetchMore ( const QModelIndex & parentValue )
 //------------------------------------------------------------------------------
 Qt::ItemFlags ctkDICOMModel::flags ( const QModelIndex & modelIndex ) const
 {
-  Q_UNUSED(modelIndex);
-  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+  Q_D(const ctkDICOMModel);
+  Qt::ItemFlags indexFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+  if (modelIndex.column() != 0)
+    {
+    return indexFlags;
+    }
+  Node* node = d->nodeFromIndex(modelIndex);
+  if (!node)
+    {
+    return indexFlags;
+    }
+  bool checkable = false;
+  node->Data[Qt::CheckStateRole].toInt(&checkable);
+  indexFlags = indexFlags | (checkable ? Qt::ItemIsUserCheckable : Qt::NoItemFlags);
+  return indexFlags;
 }
 
 //------------------------------------------------------------------------------
@@ -580,6 +605,24 @@ int ctkDICOMModel::rowCount ( const QModelIndex & parentValue ) const
 }
 
 //------------------------------------------------------------------------------
+bool ctkDICOMModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+  Q_D(const ctkDICOMModel);
+  if (role != Qt::CheckStateRole)
+    {
+    return false;
+    }
+  Node* node = d->nodeFromIndex(index);
+  if (!node || node->Data[role] == value)
+    {
+    return false;
+    }
+  node->Data[role] = value;
+  emit dataChanged(index, index);
+  return true;
+}
+
+//------------------------------------------------------------------------------
 void ctkDICOMModel::setDatabase(const QSqlDatabase &db)
 {
   Q_D(ctkDICOMModel);

+ 1 - 0
Libs/DICOM/Core/ctkDICOMModel.h

@@ -49,6 +49,7 @@ public:
   virtual QModelIndex index ( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
   virtual QModelIndex parent ( const QModelIndex & index ) const;
   virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
+  virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
   virtual bool setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole );
   // Sorting resets the model because fetched/unfetched items could disappear/appear respectively.
   virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);

+ 1 - 0
Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp

@@ -136,6 +136,7 @@ void ctkDICOMQueryRetrieveWidget::processQuery()
   headerView->setMovable(previousHeaderView->isMovable());
   headerView->setHighlightSections(previousHeaderView->highlightSections());
   headerView->setPropagateToItems(true);
+  headerView->setPropagateDepth(2);
   d->results->setHeader(headerView);
   // headerView is hidden because it was created with a visisble parent widget 
   headerView->setHidden(false);

+ 43 - 1
Libs/Widgets/ctkCheckableHeaderView.cpp

@@ -74,12 +74,15 @@ public:
   ctkCheckableHeaderViewPrivate(ctkCheckableHeaderView& object);
   ~ctkCheckableHeaderViewPrivate();
   void init();
+  void setIndexCheckState(const QModelIndex& index, Qt::CheckState checkState,
+                          int depth);
 
   int Pressed;
   ctkCheckBoxPixmaps* CheckBoxPixmaps;
   bool HeaderIsUpdating;
   bool ItemsAreUpdating;
   bool PropagateToItems;
+  int  PropagateDepth;
 };
 
 //----------------------------------------------------------------------------
@@ -91,6 +94,7 @@ ctkCheckableHeaderViewPrivate::ctkCheckableHeaderViewPrivate(ctkCheckableHeaderV
   this->CheckBoxPixmaps = 0;
   this->Pressed = -1;
   this->PropagateToItems = true;
+  this->PropagateDepth = -1;
 }
 
 //-----------------------------------------------------------------------------
@@ -111,6 +115,29 @@ void ctkCheckableHeaderViewPrivate::init()
 }
 
 //----------------------------------------------------------------------------
+void ctkCheckableHeaderViewPrivate::setIndexCheckState(
+  const QModelIndex& index, Qt::CheckState checkState, int depth)
+{
+  Q_Q(ctkCheckableHeaderView);
+  if (depth > this->PropagateDepth && this->PropagateDepth != -1)
+    {
+    return;
+    }
+  q->model()->setData(index, checkState, Qt::CheckStateRole);
+  // there is no sense to go recursive if we are vertical
+  if (q->orientation() != Qt::Horizontal)
+    {
+    return;
+    } 
+  ++depth;
+  const int rowCount = q->model()->rowCount(index);
+  for (int row = 0; row < rowCount; ++row)
+    {
+    this->setIndexCheckState(index.child(row, 0), checkState, depth);
+    }
+}
+
+//----------------------------------------------------------------------------
 ctkCheckableHeaderView::ctkCheckableHeaderView(
   Qt::Orientation orient, QWidget *widgetParent)
   : QHeaderView(orient, widgetParent)
@@ -246,6 +273,21 @@ bool ctkCheckableHeaderView::propagateToItems()const
 }
 
 //-----------------------------------------------------------------------------
+void ctkCheckableHeaderView::setPropagateDepth(int depth)
+{
+  Q_D(ctkCheckableHeaderView);
+  d->PropagateDepth = depth;
+  //TODO: rescan the model
+}
+
+//-----------------------------------------------------------------------------
+int ctkCheckableHeaderView::propagateDepth()const
+{
+  Q_D(const ctkCheckableHeaderView);
+  return d->PropagateDepth;
+}
+
+//-----------------------------------------------------------------------------
 void ctkCheckableHeaderView::toggleCheckState(int section)
 {
   // If the section is checkable, toggle the check state.
@@ -324,7 +366,7 @@ void ctkCheckableHeaderView::updateHeaders(int firstSection, int lastSection)
           QModelIndex index = this->orientation() == Qt::Horizontal ? 
             current->index(j, i,this->rootIndex()) :
             current->index(i, j,this->rootIndex()) ;
-          current->setData(index, checkState, Qt::CheckStateRole);
+          d->setIndexCheckState(index, checkState, 1);
           }
         }
       }

+ 8 - 0
Libs/Widgets/ctkCheckableHeaderView.h

@@ -69,10 +69,13 @@ class ctkCheckableHeaderViewPrivate;
 /// all items in the header row/column of the QAbstractItemModel if the 
 /// items are checkable.
 /// ctkCheckableHeaderView also supports row/column sorting.
+/// TBD: It should probably be a QSortFilterProxyModel that adds a checkability
+/// data on top of the indexes.
 class CTK_WIDGETS_EXPORT ctkCheckableHeaderView : public QHeaderView
 {
   Q_OBJECT;
   Q_PROPERTY(bool propagateToItems READ propagateToItems WRITE setPropagateToItems);
+  Q_PROPERTY(int propagateDepth READ propagateDepth WRITE setPropagateDepth);
 public:
   ctkCheckableHeaderView(Qt::Orientation orient, QWidget *parent=0);
   virtual ~ctkCheckableHeaderView();
@@ -118,6 +121,11 @@ public:
   void setPropagateToItems(bool propagate);
   bool propagateToItems()const;
 
+  /// How deep in the model(tree) do you want the check state to be propagated
+  /// A value of -1 correspond to the deepest level of the model.
+  void setPropagateDepth(int depth);
+  int  propagateDepth()const;
+
 public slots:
   ///
   /// if the check state is PartiallyChecked, the section becomes Checked