浏览代码

Add test to ctkCheckableHeaderView

Fix a behavior: make sure the checkable state of the header is updated
when setPropagateToItems is set to true.
Julien Finet 14 年之前
父节点
当前提交
6aca4b0af5

+ 197 - 13
Libs/Widgets/Testing/Cpp/ctkCheckableHeaderViewTest1.cpp

@@ -21,10 +21,12 @@
 // Qt includes
 #include <QDebug>
 #include <QApplication>
+#include <QFocusEvent>
 #include <QTableView>
 #include <QFileSystemModel>
 #include <QStandardItem>
 #include <QStandardItemModel>
+#include <QTimer>
 
 // CTK includes
 #include "ctkCheckableHeaderView.h"
@@ -43,32 +45,214 @@ int ctkCheckableHeaderViewTest1(int argc, char * argv [] )
     model.setRootPath(QDir::currentPath());
 #else
     QStandardItemModel model;
-    QStandardItem item;
-    item.insertColumns(0, 5);
-    item.insertRows(0, 7);
-    model.insertRow(0, &item);
+    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
 
   QTableView table;
   table.setModel(&model);
 
-
   model.setHeaderData(0, Qt::Horizontal, Qt::Checked, Qt::CheckStateRole);
+
   QHeaderView* previousHeaderView = table.horizontalHeader();
-  ctkCheckableHeaderView* headerView = new ctkCheckableHeaderView(Qt::Horizontal, &table);
-  qDebug() << previousHeaderView->isClickable();
-  headerView->setClickable(previousHeaderView->isClickable());
+  bool oldClickable = previousHeaderView->isClickable();
+
+  ctkCheckableHeaderView* headerView = new ctkCheckableHeaderView(Qt::Horizontal, &table);  
+  headerView->setClickable(oldClickable);
   headerView->setMovable(previousHeaderView->isMovable());
   headerView->setHighlightSections(previousHeaderView->highlightSections());
   headerView->setPropagateToItems(true);
 
+  // sets the model to the headerview
   table.setHorizontalHeader(headerView);
-  qDebug() << headerView->isCheckable(0);
+  
+  if (headerView->isClickable() != oldClickable)
+    {
+    std::cerr << "ctkCheckableHeaderView::setClickable() failed: "
+              << headerView->isClickable() << std::endl;
+    return EXIT_FAILURE;
+    }
+  if (headerView->checkState(0) == Qt::Unchecked)
+    {
+    std::cerr << "ctkCheckableHeaderView::checkstate() failed: "
+              << headerView->checkState(0) << std::endl;
+    return EXIT_FAILURE;
+    }
+  Qt::CheckState checkstate;
+  if (!headerView->checkState(0, checkstate))
+    {
+    std::cerr << "ctkCheckableHeaderView::checkstate() failed: "
+              << headerView->checkState(0, checkstate) << std::endl;
+    return EXIT_FAILURE;
+    }
+  QFocusEvent focus(QEvent::FocusIn,Qt::TabFocusReason);
+  headerView->eventFilter(headerView, &focus);
+  
+  if (!headerView->propagateToItems())
+    {
+    std::cerr << "ctkCheckableHeaderView::propagateToItems() failed: "
+              << headerView->propagateToItems() << std::endl;
+    return EXIT_FAILURE;
+    }
+  headerView->setPropagateToItems(false);
+  if (headerView->propagateToItems())
+    {
+    std::cerr << "ctkCheckableHeaderView::propagateToItems() failed: "
+              << headerView->propagateToItems() << std::endl;
+    return EXIT_FAILURE;
+    }
 
-  table.show();
-  table.raise();
+  // uncheck the header
+  headerView->toggleCheckState(0);
+  
+  if (headerView->checkState(0) != Qt::Unchecked)
+    {
+    std::cerr << "ctkCheckableHeaderView::toggleCheckState() failed: "
+              << headerView->checkState(0) << std::endl;
+    return EXIT_FAILURE;
+    }
+    
+  // 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)
+    {
+    std::cerr << "ctkCheckableHeaderView::toggleCheckState() failed: "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  row0[0]->setCheckState(Qt::Unchecked);
+  // 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)
+    {
+    std::cerr << "QStandardItem::setCheckState() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  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)
+    {
+    std::cerr << "ctkCheckableHeaderView::setPropagateToItems() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
 
-  //app.exec();
+  row0[0]->setCheckState(Qt::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: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  row1[0]->setCheckState(Qt::Unchecked);
+  
+    // 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)
+    {
+    std::cerr << "QStandardItem::setCheckState() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  row1[0]->setCheckState(Qt::Unchecked);
+  
+  // 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)
+    {
+    std::cerr << "QStandardItem::setCheckState() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  row0[0]->setCheckState(Qt::Unchecked);
+  row2[0]->setCheckState(Qt::Unchecked);
+
+  // 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)
+    {
+    std::cerr << "QStandardItem::setCheckState() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  headerView->setCheckState(0, Qt::Checked);
+    
+  if (headerView->checkState(0) != Qt::Checked ||
+      row0[0]->checkState() != Qt::Checked ||
+      row1[0]->checkState() != Qt::Checked ||
+      row2[0]->checkState() != Qt::Checked)
+    {
+    std::cerr << "ctkCheckableHeaderView::setCheckState() failed: "
+              << headerView->checkState(0) << " "
+              << row0[0]->checkState() << " "
+              << row1[0]->checkState() << " "
+              << row2[0]->checkState() << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  table.show();
+  //table.raise();
 
-  return EXIT_SUCCESS;
+  if (argc < 2 || QString(argv[1]) != "-I" )
+    {
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    }
+  
+  return app.exec();
 }

+ 28 - 7
Libs/Widgets/ctkCheckableHeaderView.cpp

@@ -214,6 +214,10 @@ void ctkCheckableHeaderView::setRootIndex(const QModelIndex &index)
 void ctkCheckableHeaderView::setPropagateToItems(bool propagate)
 {
   Q_D(ctkCheckableHeaderView);
+  if (d->PropagateToItems == propagate)
+    {
+    return;
+    }
   d->PropagateToItems = propagate;
   if (!this->model())
     {
@@ -224,6 +228,7 @@ void ctkCheckableHeaderView::setPropagateToItems(bool propagate)
     this->connect(
       this->model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
       this, SLOT(updateHeadersFromItems(const QModelIndex&, const QModelIndex&)));
+    this->updateHeadersFromItems();
     }
   else
     {
@@ -270,17 +275,18 @@ void ctkCheckableHeaderView::setCheckState(int section, Qt::CheckState checkStat
 
 //-----------------------------------------------------------------------------
 void ctkCheckableHeaderView::updateHeaderData(Qt::Orientation orient,
-                                               int first, int last)
+                                              int firstSection,
+                                              int lastSection)
 {
   if(orient != this->orientation())
     {
     return;
     }
-  this->updateHeaders(first, last);
+  this->updateHeaders(firstSection, lastSection);
 }
 
 //-----------------------------------------------------------------------------
-void ctkCheckableHeaderView::updateHeaders(int first, int last)
+void ctkCheckableHeaderView::updateHeaders(int firstSection, int lastSection)
 {
   Q_D(ctkCheckableHeaderView);
   if(d->HeaderIsUpdating)
@@ -291,8 +297,8 @@ void ctkCheckableHeaderView::updateHeaders(int first, int last)
   QAbstractItemModel *current = this->model();
   Q_ASSERT(current);
 
-  first = qBound(0, first, this->count() -1);
-  last = qBound(0, last, this->count() -1);
+  firstSection = qBound(0, firstSection, this->count() -1);
+  lastSection = qBound(0, lastSection, this->count() -1);
 
   bool active = true;
   if(this->parentWidget())
@@ -302,7 +308,7 @@ void ctkCheckableHeaderView::updateHeaders(int first, int last)
   int maxJ = this->orientation() == Qt::Horizontal ? 
     current->rowCount() : current->columnCount();
   
-  for(int i = first; i <= last; i++)
+  for(int i = firstSection; i <= lastSection; i++)
     {
     QVariant decoration;
     Qt::CheckState checkState;
@@ -329,8 +335,23 @@ void ctkCheckableHeaderView::updateHeaders(int first, int last)
 }
 
 //-----------------------------------------------------------------------------
+void ctkCheckableHeaderView::updateHeadersFromItems()
+{
+  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);
+}
+
+//-----------------------------------------------------------------------------
 void ctkCheckableHeaderView::updateHeadersFromItems(const QModelIndex & topLeft,
-                                                     const QModelIndex & bottomRight)
+                                                    const QModelIndex & bottomRight)
 {
   Q_UNUSED(bottomRight);
   Q_D(ctkCheckableHeaderView);

+ 6 - 1
Libs/Widgets/ctkCheckableHeaderView.h

@@ -112,6 +112,8 @@ public:
   ///
   /// If true, the items check states in a row/column are synchronized 
   /// with the check state of the corresponding header section.
+  /// When the property is set to true, the checkstate of the header is
+  /// automatically updated from the checkstate of the items
   void setPropagateToItems(bool propagate);
   bool propagateToItems()const;
 
@@ -126,10 +128,13 @@ public slots:
 
 private slots:
   void updateHeaderData(Qt::Orientation orient, int first, int last);
+
   void insertHeaderSection(const QModelIndex &parent, int first, int last);
   inline void updateHeaders();
-  void updateHeadersFromItems(const QModelIndex& topLeft, const QModelIndex& bottomRight);
 
+  void updateHeadersFromItems(const QModelIndex& topLeft, const QModelIndex& bottomRight);
+  void updateHeadersFromItems();
+  
 protected:
   virtual void updateHeaders(int first, int last);
   virtual void initStyleSectionOption(QStyleOptionHeader *option, int section, QRect rect)const;