Browse Source

Fix initialization of ctkCheckableHeaderView

When models are set to ctkCheckableHeaderView, makes sure that the proper
check state is updated based on the check state of the items if
propagateToItems is true (default).
Julien Finet 14 years ago
parent
commit
5abf277529

+ 101 - 73
Libs/Widgets/Testing/Cpp/ctkCheckableHeaderViewTest1.cpp

@@ -40,40 +40,50 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
 {
   QApplication app(argc, argv);
 
-#if 0
-    QFileSystemModel model;
-    model.setRootPath(QDir::currentPath());
-#else
-    QStandardItemModel model;
-    QList<QStandardItem*> row0;
-    row0 << new QStandardItem << new QStandardItem << new QStandardItem;
-    row0[0]->setText("not user checkable");
-    model.appendRow(row0);
-    QList<QStandardItem*> row1;
-    row1 << new QStandardItem << new QStandardItem << new QStandardItem;
-    row1[0]->setCheckable(true);
-    row1[0]->setText("checkable");
-    model.appendRow(row1);
-    QList<QStandardItem*> row2;
-    row2 << new QStandardItem << new QStandardItem << new QStandardItem;
-    row2[0]->setCheckable(true);
-    row2[0]->setText("checkable");
-    model.appendRow(row2);
-#endif
+  QStandardItemModel model;
+  QList<QStandardItem*> row0;
+  row0 << new QStandardItem << new QStandardItem << new QStandardItem;
+  row0[0]->setText("not user checkable");
+  model.appendRow(row0);
+  QList<QStandardItem*> row1;
+  row1 << new QStandardItem << new QStandardItem << new QStandardItem;
+  row1[0]->setCheckable(true);
+  row1[0]->setText("checkable");
+  model.appendRow(row1);
+  QList<QStandardItem*> row2;
+  row2 << new QStandardItem << new QStandardItem << new QStandardItem;
+  row2[0]->setCheckable(true);
+  row2[0]->setText("checkable");
+  model.appendRow(row2);
+
+  // items are unchecked by default 
+  if (row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
+    {
+    std::cerr << "QStandardItem default failed: "
+	      << static_cast<int>(row0[0]->checkState()) << " "
+              << static_cast<int>(row1[0]->checkState()) << " "
+              << static_cast<int>(row2[0]->checkState()) << std::endl;
+    return EXIT_FAILURE;
+    }
 
   QTableView table;
   table.setModel(&model);
 
+  // Header is checked by default
   model.setHeaderData(0, Qt::Horizontal, Qt::Checked, Qt::CheckStateRole);
 
   QHeaderView* previousHeaderView = table.horizontalHeader();
   bool oldClickable = previousHeaderView->isClickable();
 
-  ctkCheckableHeaderView* headerView = new ctkCheckableHeaderView(Qt::Horizontal, &table);  
+  ctkCheckableHeaderView* headerView =
+    new ctkCheckableHeaderView(Qt::Horizontal, &table);
   headerView->setClickable(oldClickable);
   headerView->setMovable(previousHeaderView->isMovable());
   headerView->setHighlightSections(previousHeaderView->highlightSections());
-  headerView->setPropagateToItems(true);
+  // propagatetoitems is true by default
+  //headerView->setPropagateToItems(true);
 
   // sets the model to the headerview
   table.setHorizontalHeader(headerView);
@@ -84,19 +94,30 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
               << headerView->isClickable() << std::endl;
     return EXIT_FAILURE;
     }
-  if (headerView->checkState(0) == Qt::Unchecked)
+  // As propagateToItems is true, once the model is set to the headerview,
+  // the checkable header is updated from the check state of all the items
+  // all the items are unchecked by default, so the header becomes unchecked
+  if (headerView->checkState(0) != Qt::Unchecked ||
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "ctkCheckableHeaderView::checkstate() failed: "
-              << static_cast<int>(headerView->checkState(0)) << std::endl;
+              << static_cast<int>(headerView->checkState(0)) << " "
+	      << static_cast<int>(row0[0]->checkState()) << " "
+              << static_cast<int>(row1[0]->checkState()) << " "
+              << static_cast<int>(row2[0]->checkState()) << std::endl;
     return EXIT_FAILURE;
     }
+  // Retrieve checkstate of the header
   Qt::CheckState checkstate;
   if (!headerView->checkState(0, checkstate))
     {
     std::cerr << "ctkCheckableHeaderView::checkstate() failed: "
-              << static_cast<int>(headerView->checkState(0, checkstate)) << std::endl;
+              << static_cast<int>(checkstate) << std::endl;
     return EXIT_FAILURE;
     }
+
   QFocusEvent focus(QEvent::FocusIn,Qt::TabFocusReason);
   headerView->eventFilter(headerView, &focus);
   
@@ -113,35 +134,42 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
               << headerView->propagateToItems() << std::endl;
     return EXIT_FAILURE;
     }
-
-  // uncheck the header
-  headerView->toggleCheckState(0);
-  
-  if (headerView->checkState(0) != Qt::Unchecked)
+  if (headerView->checkState(0) != Qt::Unchecked ||
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
-    std::cerr << "ctkCheckableHeaderView::toggleCheckState() failed: "
-              << static_cast<int>(headerView->checkState(0)) << std::endl;
+    std::cerr << "ctkCheckableHeaderView::propagateToItems() failed: "
+              << static_cast<int>(headerView->checkState(0)) << " "
+	      << static_cast<int>(row0[0]->checkState()) << " "
+              << static_cast<int>(row1[0]->checkState()) << " "
+              << static_cast<int>(row2[0]->checkState()) << std::endl;
     return EXIT_FAILURE;
     }
-    
+
+  // check the header
+  headerView->toggleCheckState(0);
+  
   // make sure it didn't uncheck the checkable items
-  if (row0[0]->checkState() != Qt::Checked ||
-      row1[0]->checkState() != Qt::Checked ||
-      row2[0]->checkState() != Qt::Checked)
+  if (headerView->checkState(0) != Qt::Checked ||
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
-    std::cerr << "ctkCheckableHeaderView::toggleCheckState() failed: "
-              << static_cast<int>(row0[0]->checkState()) << " "
+    std::cerr << __LINE__ << " ctkCheckableHeaderView::toggleCheckState() failed: "
+              << static_cast<int>(headerView->checkState(0)) << " "
+	      << static_cast<int>(row0[0]->checkState()) << " "
               << static_cast<int>(row1[0]->checkState()) << " "
               << static_cast<int>(row2[0]->checkState()) << std::endl;
     return EXIT_FAILURE;
     }
 
-  row0[0]->setCheckState(Qt::Unchecked);
+  row0[0]->setCheckState(Qt::Checked);
   // make sure it didn't uncheck the checkable items
-  if (headerView->checkState(0) != Qt::Unchecked ||
-      row0[0]->checkState() != Qt::Unchecked ||
-      row1[0]->checkState() != Qt::Checked ||
-      row2[0]->checkState() != Qt::Checked)
+  if (headerView->checkState(0) != Qt::Checked ||
+      row0[0]->checkState() != Qt::Checked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "QStandardItem::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -151,13 +179,14 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
+  // The checkable header gets updated with the item check states
   headerView->setPropagateToItems(true);
 
   if (!headerView->propagateToItems() ||
       headerView->checkState(0) != Qt::PartiallyChecked ||
-      row0[0]->checkState() != Qt::Unchecked ||
-      row1[0]->checkState() != Qt::Checked ||
-      row2[0]->checkState() != Qt::Checked)
+      row0[0]->checkState() != Qt::Checked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "ctkCheckableHeaderView::setPropagateToItems() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -167,12 +196,12 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  row0[0]->setCheckState(Qt::Checked);
+  row0[0]->setCheckState(Qt::Unchecked);
   
-  if (headerView->checkState(0) != Qt::Checked ||
-      row0[0]->checkState() != Qt::Checked ||
-      row1[0]->checkState() != Qt::Checked ||
-      row2[0]->checkState() != Qt::Checked)
+  if (headerView->checkState(0) != Qt::Unchecked ||
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "QStandardItem::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -182,13 +211,13 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  row1[0]->setCheckState(Qt::Unchecked);
+  row1[0]->setCheckState(Qt::Checked);
   
     // make sure it didn't uncheck the checkable items
   if (headerView->checkState(0) != Qt::PartiallyChecked ||
-      row0[0]->checkState() != Qt::Checked ||
-      row1[0]->checkState() != Qt::Unchecked ||
-      row2[0]->checkState() != Qt::Checked)
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Checked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "QStandardItem::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -198,13 +227,13 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  row1[0]->setCheckState(Qt::Unchecked);
+  row1[0]->setCheckState(Qt::Checked);
   
-  // make sure it didn't uncheck the checkable items
+  // make sure it didn't check the checkable items
   if (headerView->checkState(0) != Qt::PartiallyChecked ||
-      row0[0]->checkState() != Qt::Checked ||
-      row1[0]->checkState() != Qt::Unchecked ||
-      row2[0]->checkState() != Qt::Checked)
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Checked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "QStandardItem::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -214,14 +243,14 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  row0[0]->setCheckState(Qt::Unchecked);
-  row2[0]->setCheckState(Qt::Unchecked);
+  row0[0]->setCheckState(Qt::Checked);
+  row2[0]->setCheckState(Qt::Checked);
 
-  // make sure the header is now unchecked
-  if (headerView->checkState(0) != Qt::Unchecked ||
-      row0[0]->checkState() != Qt::Unchecked ||
-      row1[0]->checkState() != Qt::Unchecked ||
-      row2[0]->checkState() != Qt::Unchecked)
+  // make sure the header is now checked
+  if (headerView->checkState(0) != Qt::Checked ||
+      row0[0]->checkState() != Qt::Checked ||
+      row1[0]->checkState() != Qt::Checked ||
+      row2[0]->checkState() != Qt::Checked)
     {
     std::cerr << "QStandardItem::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -231,12 +260,12 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  headerView->setCheckState(0, Qt::Checked);
+  headerView->setCheckState(0, Qt::Unchecked);
     
-  if (headerView->checkState(0) != Qt::Checked ||
-      row0[0]->checkState() != Qt::Checked ||
-      row1[0]->checkState() != Qt::Checked ||
-      row2[0]->checkState() != Qt::Checked)
+  if (headerView->checkState(0) != Qt::Unchecked ||
+      row0[0]->checkState() != Qt::Unchecked ||
+      row1[0]->checkState() != Qt::Unchecked ||
+      row2[0]->checkState() != Qt::Unchecked)
     {
     std::cerr << "ctkCheckableHeaderView::setCheckState() failed: "
               << static_cast<int>(headerView->checkState(0)) << " "
@@ -247,7 +276,6 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     }
 
   table.show();
-  //table.raise();
 
   if (argc < 2 || QString(argv[1]) != "-I" )
     {

+ 21 - 13
Libs/Widgets/ctkCheckableHeaderView.cpp

@@ -339,14 +339,25 @@ void ctkCheckableHeaderView::setModel(QAbstractItemModel *newModel)
     }
 
   // Determine which sections are clickable and setup the icons.
-  this->updateHeaders();
+  if (d->PropagateToItems)
+    {
+    this->updateHeadersFromItems();
+    }
+  else
+    {
+    this->updateHeaders();
+    }
 }
 
 //-----------------------------------------------------------------------------
 void ctkCheckableHeaderView::setRootIndex(const QModelIndex &index)
 {
+  Q_D(ctkCheckableHeaderView);
   this->QHeaderView::setRootIndex(index);
-  this->updateHeaders();
+  if (d->PropagateToItems)
+    {
+    this->updateHeadersFromItems();
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -416,19 +427,19 @@ void ctkCheckableHeaderView::toggleCheckState(int section)
 void ctkCheckableHeaderView::setCheckState(int section, Qt::CheckState checkState)
 {
   Q_D(ctkCheckableHeaderView);
-  // If the section is checkable, toggle the check state.
   QAbstractItemModel *current = this->model();
   if(current == 0)
     {    
     return;
     }
-  // If the state is unchecked or partially checked, the state
-  // should be changed to checked.
   current->setHeaderData(section, this->orientation(),
                          checkState, Qt::CheckStateRole);
-  d->ItemsAreUpdating = true;
-  d->propagateCheckStateToChildren(this->rootIndex());
-  d->ItemsAreUpdating = false;
+  if (d->PropagateToItems)
+    {
+    d->ItemsAreUpdating = true;
+    d->propagateCheckStateToChildren(this->rootIndex());
+    d->ItemsAreUpdating = false;
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -479,16 +490,13 @@ void ctkCheckableHeaderView::updateHeaders(int firstSection, int lastSection)
 //-----------------------------------------------------------------------------
 void ctkCheckableHeaderView::updateHeadersFromItems()
 {
+  Q_D(ctkCheckableHeaderView);
   QAbstractItemModel *currentModel = this->model();
   if (!currentModel)
     {
     return;
     }
-  QModelIndex firstIndex = currentModel->index(0,0);
-  QModelIndex lastIndex =
-    currentModel->index(currentModel->rowCount() - 1,
-                        currentModel->columnCount() -1);
-  this->updateHeadersFromItems(firstIndex, lastIndex);
+  d->updateCheckState(QModelIndex());
 }
 
 //-----------------------------------------------------------------------------

+ 8 - 1
Libs/Widgets/ctkCheckableHeaderView.h

@@ -80,7 +80,13 @@ public:
   ctkCheckableHeaderView(Qt::Orientation orient, QWidget *parent=0);
   virtual ~ctkCheckableHeaderView();
 
-  /// Reimplemented for internal reasons
+  ///
+  /// When setting the model, if PropagateToItems is true (by default), the check
+  /// state of the checkable headers is updated from the check state of the items
+  /// If you want to make sure of the check state of a header, after setting the
+  /// (done by myView.setHeader(myCheckableHeaderView)), you can call
+  /// myModel.setHeaderData(0, Qt::Horizontal, Qt::Checked, Qt::CheckStateRole)
+  /// or myCheckableHeaderView->setCheckState(0, Qt::Checked)
   virtual void setModel(QAbstractItemModel *model);
 
   /// Reimplemented for internal reasons
@@ -123,6 +129,7 @@ public:
 
   /// 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.
+  /// -1 by default
   void setPropagateDepth(int depth);
   int  propagateDepth()const;