浏览代码

ENH: faster version of qCTKDCMTKModel

Julien Finet 15 年之前
父节点
当前提交
13c809485a

文件差异内容过多而无法显示
+ 8 - 8
Libs/DICOM/Core/Resources/dicom-sample.sql


+ 1 - 1
Libs/DICOM/Core/Testing/CMakeLists.txt

@@ -18,5 +18,5 @@ IF(WIN32)
   SET(CTKDICOMCore_TESTS ${CXX_TEST_PATH}/${CMAKE_BUILD_TYPE}/${KIT}CxxTests)
 ENDIF(WIN32)
 
-ADD_TEST( qCTKDCMTKModelTest1 ${CTKDICOMCore_TESTS} qCTKDCMTKModelTest1 ../../Resources/dicom-sample.sql)
+ADD_TEST( qCTKDCMTKModelTest1 ${CTKDICOMCore_TESTS} qCTKDCMTKModelTest1 ${CMAKE_CURRENT_BINARY_DIR}/dicom.db ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/dicom-sample.sql)
 ADD_TEST( qCTKDCMTKTest1 ${CTKDICOMCore_TESTS} qCTKDCMTKTest1 ${CMAKE_CURRENT_BINARY_DIR}/dicom.db ${CMAKE_CURRENT_SOURCE_DIR}/../Resources/dicom-sample.sql)

+ 22 - 10
Libs/DICOM/Core/Testing/qCTKDCMTKModelTest1.cxx

@@ -2,7 +2,9 @@
 #include <QDebug>
 #include <QFileInfo>
 #include <QTreeView>
+#include <QSqlQuery>
 
+#include "qCTKDCMTK.h"
 #include "qCTKDCMTKModel.h"
 
 #include <iostream>
@@ -10,23 +12,33 @@
 int qCTKDCMTKModelTest1( int argc, char * argv [] )
 {
   QApplication app(argc, argv);
-
-  qCTKDCMTKModel model(0);
+  
   if (argc <= 1)
     {
     std::cerr << "Warning, no sql file given. Test stops" << std::endl;
-    return EXIT_SUCCESS;
-    }
-  if (!QFileInfo(argv[1]).exists())
-    {
-    std::cerr << "Invalid sql file." << std::endl;
     return EXIT_FAILURE;
     }
-    
+  
+  qCTKDCMTK myCTK;
+  myCTK.openDatabase( argv[1] );
+  myCTK.initializeDatabase(argv[2]);
+  /*
+  QSqlQuery toto("SELECT * FROM Patients", myCTK.database());
+  qDebug() << "toto: " << myCTK.GetLastError() << toto.seek(0) << myCTK.GetLastError();
+  QSqlQuery titi("SELECT StudyID as UID, StudyDescription as Name, ModalitiesInStudy as Scan, StudyDate as Date, AccessionNumber as Number, ReferringPhysician as Institution, ReferringPhysician as Referrer, PerformingPysiciansName as Performer FROM Studies WHERE PatientsUID='14'", myCTK.database());
+  qDebug() << "titi: " << titi.seek(0) << myCTK.GetLastError();
+  QSqlQuery tata("SELECT SeriesInstanceUID as UID, BodyPartExamined as Scan, SeriesDate as Date, AcquisitionNumber as Number FROM Series WHERE StudyInstanceUID='1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162'", myCTK.database());
+  qDebug() << "tata: " << tata.seek(0) << myCTK.GetLastError();
+  QSqlQuery tutu("SELECT Filename as UID, Filename as Name, SeriesInstanceUID as Date FROM Images WHERE SeriesInstanceUID='%1'", myCTK.database());
+  qDebug() << "tutu: " << tutu.seek(0) << myCTK.GetLastError();
+  */
+
+  qCTKDCMTKModel model(0);
+  model.setDatabase(myCTK.database());
+
   QTreeView viewer(0);
   viewer.setModel(&model);
-  
-  model.setDataBase(argv[1]);
+  viewer.setSortingEnabled(true);
 
   model.rowCount();
   qDebug() << model.rowCount() << model.columnCount();

+ 1 - 1
Libs/DICOM/Core/Testing/qCTKDCMTKTest1.cxx

@@ -6,7 +6,7 @@
 #include <iostream>
 #include <cstdlib>
 
-int qCTKDCMTKTest1(int argc, char** argv) {
+int qCTKDCMTKTest1(int argc, char * argv []) {
   
   QApplication app(argc, argv);
   QTextStream out(stdout);

+ 433 - 549
Libs/DICOM/Core/qCTKDCMTKModel.cxx

@@ -1,549 +1,433 @@
-#include <QStringList>
-#include <QSqlQuery>
-#include <QSqlQueryModel>
-#include <QTime>
-#include <QDebug>
-
-#include "qCTKDCMTKModel.h"
-
-struct Node
-{
-  Node* Parent;
-  int   Row;
-  int   Column;
-};
-
-class qCTKDCMTKModelPrivate:public qCTKPrivate<qCTKDCMTKModel>
-{
-public:
-  qCTKDCMTKModelPrivate();
-  ~qCTKDCMTKModelPrivate();
-  void init();
-
-  enum IndexType{
-    RootType,
-    PatientType,
-    StudyType,
-    SeriesType,
-    ImageType
-  };
-  IndexType indexType(const QModelIndex& index)const;
-
-  void updateRootModel(const QModelIndex& index);
-  void updatePatientModel(const QModelIndex& index);
-  void updateStudyModel(const QModelIndex& index);
-  void updateSeriesModel(const QModelIndex& index);
-
-  QModelIndex indexInRootQuery(const QModelIndex& index)const;
-  QModelIndex indexInPatientQuery(const QModelIndex& index)const;
-  QModelIndex indexInStudyQuery(const QModelIndex& index)const;
-  QModelIndex indexInSeriesQuery(const QModelIndex& index)const;
-  
-  QSqlDatabase    DataBase;
-  QSqlQueryModel* RootModel;
-  QSqlQueryModel* PatientModel;
-  QSqlQueryModel* StudyModel;
-  QSqlQueryModel* SeriesModel;
-
-  Node*           RootNode;
-  Node*           PatientNode;
-  Node*           StudyNode;
-  Node*           SeriesNode;
-  mutable QList<Node*>    Nodes;
-};
-
-qCTKDCMTKModelPrivate::qCTKDCMTKModelPrivate()
-  :DataBase(QSqlDatabase::addDatabase("QSQLITE", "DICOM-DB"))
-{
-  this->RootModel    = 0;
-  this->PatientModel = 0;
-  this->StudyModel   = 0;
-  this->SeriesModel  = 0;
-  this->RootNode     = 0;
-  this->PatientNode  = 0;
-  this->StudyNode    = 0;
-  this->SeriesNode   = 0;
-}
-
-qCTKDCMTKModelPrivate::~qCTKDCMTKModelPrivate()
-{
-  foreach(Node* node, this->Nodes)
-    {
-    delete node;
-    }
-  this->Nodes.clear();
-
-}
-
-void qCTKDCMTKModelPrivate::init()
-{
-  QCTK_P(qCTKDCMTKModel);
-  this->RootModel = new QSqlQueryModel(p);
-  this->PatientModel = new QSqlQueryModel(p);
-  this->StudyModel = new QSqlQueryModel(p);
-  this->SeriesModel = new QSqlQueryModel(p);
-
-  QObject::connect(this->RootModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
-          p, SLOT(rootRowsAboutToBeInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->PatientModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
-          p, SLOT(patientRowsAboutToBeInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->StudyModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
-          p, SLOT(studyRowsAboutToBeInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->SeriesModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
-          p, SLOT(seriesRowsAboutToBeInserted(const QModelIndex&, int, int)));
-
-  QObject::connect(this->RootModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
-          p, SLOT(rootRowsInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->PatientModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
-          p, SLOT(patientRowsInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->StudyModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
-          p, SLOT(studyRowsInserted(const QModelIndex&, int, int)));
-  QObject::connect(this->SeriesModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
-          p, SLOT(seriesRowsInserted(const QModelIndex&, int, int)));
-
-  QObject::connect(this->RootModel, SIGNAL(modelAboutToBeReset()),
-          p, SLOT(onModelAboutToBeReset()));
-  QObject::connect(this->PatientModel, SIGNAL(modelAboutToBeReset()),
-          p, SLOT(onModelAboutToBeReset()));
-  QObject::connect(this->StudyModel, SIGNAL(modelAboutToBeReset()),
-          p, SLOT(onModelAboutToBeReset()));
-  QObject::connect(this->SeriesModel, SIGNAL(modelAboutToBeReset()),
-          p, SLOT(onModelAboutToBeReset()));
-
-  QObject::connect(this->RootModel, SIGNAL(modelReset()),
-          p, SLOT(onModelReset()));
-  QObject::connect(this->PatientModel, SIGNAL(modelReset()),
-          p, SLOT(onModelReset()));
-  QObject::connect(this->StudyModel, SIGNAL(modelReset()),
-          p, SLOT(onModelReset()));
-  QObject::connect(this->SeriesModel, SIGNAL(modelReset()),
-          p, SLOT(onModelReset()));
-
-  QObject::connect(this->RootModel, SIGNAL(layoutAboutToBeChanged()),
-          p, SLOT(onLayoutAboutToBeChanged()));
-  QObject::connect(this->PatientModel, SIGNAL(layoutAboutToBeChanged()),
-          p, SLOT(onLayoutAboutToBeChanged()));
-  QObject::connect(this->StudyModel, SIGNAL(layoutAboutToBeChanged()),
-          p, SLOT(onLayoutAboutToBeChanged()));
-  QObject::connect(this->SeriesModel, SIGNAL(layoutAboutToBeChanged()),
-          p, SLOT(onLayoutAboutToBeChanged()));
-
-  QObject::connect(this->RootModel, SIGNAL(layoutChanged()),
-          p, SLOT(onLayoutChanged()));
-  QObject::connect(this->PatientModel, SIGNAL(layoutChanged()),
-          p, SLOT(onLayoutChanged()));
-  QObject::connect(this->StudyModel, SIGNAL(layoutChanged()),
-          p, SLOT(onLayoutChanged()));
-  QObject::connect(this->SeriesModel, SIGNAL(layoutChanged()),
-          p, SLOT(onLayoutChanged()));
-
-  this->RootNode = new Node;
-  this->RootNode->Parent = 0;
-  this->RootNode->Row = -1;
-  this->RootNode->Column = -1;
-  this->Nodes.append(this->RootNode);
-}
-
-qCTKDCMTKModelPrivate::IndexType qCTKDCMTKModelPrivate::indexType(const QModelIndex& index)const
-{
-  QCTK_P(const qCTKDCMTKModel);
-  if (!index.isValid())
-    {
-    return RootType;
-    }
-  QModelIndex indexParent = p->parent(index);
-  if (!indexParent.isValid())
-    {
-    return PatientType;
-    }
-  indexParent = p->parent(indexParent);
-  if (!indexParent.isValid())
-    {
-    return StudyType;
-    }
-  indexParent = p->parent(indexParent);
-  if (!indexParent.isValid())
-    {
-    return SeriesType;
-    }
-  Q_ASSERT(!p->parent(indexParent).isValid());
-  return ImageType;
-}
-
-QModelIndex qCTKDCMTKModelPrivate::indexInRootQuery(const QModelIndex& index) const
-{
-  return index;
-}
-
-QModelIndex qCTKDCMTKModelPrivate::indexInPatientQuery(const QModelIndex& index) const
-{
-  return index;
-}
-
-QModelIndex qCTKDCMTKModelPrivate::indexInStudyQuery(const QModelIndex& index) const
-{
-  return index;
-}
-
-QModelIndex qCTKDCMTKModelPrivate::indexInSeriesQuery(const QModelIndex& index) const
-{
-  return index;
-}
-
-void qCTKDCMTKModelPrivate::updateRootModel(const QModelIndex& index)
-{
-  QString query("SELECT * FROM Patients");
-  if (query == this->RootModel->query().lastQuery())
-    {
-    return;
-    }
-  this->RootModel->setQuery(query, this->DataBase);
-}
-
-void qCTKDCMTKModelPrivate::updatePatientModel(const QModelIndex& index)
-{
-  QCTK_P(qCTKDCMTKModel);
-  this->PatientNode = reinterpret_cast<Node*>(index.internalPointer());
-  QString patientId = p->data(index).toString();
-  QString query = QString("SELECT * FROM Studies WHERE PatientsUID='%1'").arg(patientId);
-  if (query == this->PatientModel->query().lastQuery())
-    {
-    return;
-    }
-  this->PatientModel->setQuery( query, this->DataBase);
-}
-
-void qCTKDCMTKModelPrivate::updateStudyModel(const QModelIndex& index)
-{
-  QCTK_P(qCTKDCMTKModel);
-  this->StudyNode = reinterpret_cast<Node*>(index.internalPointer());
-  QString studyId = p->data(index).toString();
-  QString query = QString("SELECT * FROM Series WHERE StudyInstanceUID='%1'").arg(studyId);
-  if (query == this->StudyModel->query().lastQuery())
-    {
-    return;
-    }
-  this->StudyModel->setQuery(query, this->DataBase);
-}
-
-void qCTKDCMTKModelPrivate::updateSeriesModel(const QModelIndex& index)
-{
-  QCTK_P(qCTKDCMTKModel);
-  this->SeriesNode = reinterpret_cast<Node*>(index.internalPointer());
-  QString seriesId = p->data(index).toString();
-  QString query = QString("SELECT * FROM Images WHERE SeriesInstanceUID='%1'").arg(seriesId);
-  if (query == this->SeriesModel->query().lastQuery())
-    {
-    return;
-    }
-  this->SeriesModel->setQuery(query, this->DataBase);
-}
-
-qCTKDCMTKModel::qCTKDCMTKModel(QObject* parent)
-{
-  QCTK_INIT_PRIVATE(qCTKDCMTKModel);
-  qctk_d()->init();
-}
-
-qCTKDCMTKModel::~qCTKDCMTKModel()
-{
-}
-
-bool qCTKDCMTKModel::canFetchMore ( const QModelIndex & parent ) const
-{
-  QCTK_D(const qCTKDCMTKModel);
-  switch(d->indexType(parent))
-    {
-    case qCTKDCMTKModelPrivate::RootType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateRootModel(parent);
-      return d->RootModel->canFetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updatePatientModel(parent);
-      return d->PatientModel->canFetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateStudyModel(parent);
-      return d->StudyModel->canFetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateSeriesModel(parent);
-      return d->SeriesModel->canFetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::ImageType:
-    default:
-      break;
-    }
-  return false;
-}
-
-int qCTKDCMTKModel::columnCount ( const QModelIndex & _parent ) const
-{
-  Q_UNUSED(_parent);
-  return 50;
-}
-
-QVariant qCTKDCMTKModel::data ( const QModelIndex & index, int role ) const
-{
-  QCTK_D(const qCTKDCMTKModel);
-  QVariant res;
-  QModelIndex indexParent = this->parent(index);
-  switch(d->indexType(index))
-    {
-    default:
-    case qCTKDCMTKModelPrivate::RootType:
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateRootModel(indexParent);
-      res = d->RootModel->data(d->indexInRootQuery(index), role);
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updatePatientModel(indexParent);
-      res = d->PatientModel->data(d->indexInPatientQuery(index), role);
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateStudyModel(indexParent);
-      res = d->StudyModel->data(d->indexInStudyQuery(index), role);
-      break;
-    case qCTKDCMTKModelPrivate::ImageType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateSeriesModel(indexParent);
-      res = d->SeriesModel->data(d->indexInSeriesQuery(index), role);
-      break;
-    }
-  return res;
-}
-
-void qCTKDCMTKModel::fetchMore ( const QModelIndex & parent )
-{
-  QCTK_D(qCTKDCMTKModel);
-  switch(d->indexType(parent))
-    {
-    case qCTKDCMTKModelPrivate::RootType:
-      d->updateRootModel(parent);
-      d->RootModel->fetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      d->updatePatientModel(parent);
-      d->PatientModel->fetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      d->updateStudyModel(parent);
-      d->StudyModel->fetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      d->updateSeriesModel(parent);
-      d->SeriesModel->fetchMore();
-      break;
-    case qCTKDCMTKModelPrivate::ImageType:
-    default:
-      break;
-    }
-}
-
-Qt::ItemFlags qCTKDCMTKModel::flags ( const QModelIndex & index ) const
-{
-  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
-}
-
-bool qCTKDCMTKModel::hasChildren ( const QModelIndex & parent ) const
-{
-  QCTK_D(const qCTKDCMTKModel);
-  switch(d->indexType(parent))
-    {
-    case qCTKDCMTKModelPrivate::RootType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateRootModel(parent);
-      return d->RootModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updatePatientModel(parent);
-      return d->PatientModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateStudyModel(parent);
-      return d->StudyModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateSeriesModel(parent);
-      return d->SeriesModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::ImageType:
-    default:
-      break;
-    }
-  return false;
-}
-
-QModelIndex qCTKDCMTKModel::index ( int row, int column, const QModelIndex & parent ) const
-{
-  QCTK_D(const qCTKDCMTKModel);
-  QSqlQueryModel* res = 0;
-  switch(d->indexType(parent))
-    {
-    case qCTKDCMTKModelPrivate::RootType:
-      res = d->RootModel;
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      res = d->PatientModel;
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      res = d->StudyModel;
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      res = d->SeriesModel;
-      break;
-    case qCTKDCMTKModelPrivate::ImageType:
-    default:
-      Q_ASSERT(d->indexType(parent) != qCTKDCMTKModelPrivate::ImageType);
-      break;
-    }
-  Node* parentNode = 
-    reinterpret_cast<Node*>(parent.internalPointer());
-  Node* node = 0;
-  foreach(Node* tmpNode, d->Nodes)
-    {
-    if (tmpNode->Parent == parentNode &&
-        tmpNode->Row == row && 
-        tmpNode->Column == column)
-      {
-      node = tmpNode;
-      break;
-      }
-    }
-  if ( node == 0)
-    {
-    node = new Node;
-    node->Parent = parentNode;
-    node->Row = row;
-    node->Column = column;
-    d->Nodes.append(node);
-    }
-  return this->createIndex(row, column, node);
-}
-
-QModelIndex qCTKDCMTKModel::parent ( const QModelIndex & index ) const
-{
-  Node* node = 
-    reinterpret_cast<Node*>(index.internalPointer());
-  if (node == 0 || node->Parent == 0)
-    {
-    return QModelIndex();
-    }
-  return this->createIndex(node->Parent->Row, node->Parent->Column, node->Parent);
-}
-
-int qCTKDCMTKModel::rowCount ( const QModelIndex & parent ) const
-{
-  QCTK_D(const qCTKDCMTKModel);
-  int res = 0;
-  switch(d->indexType(parent))
-    {
-    default:
-    case qCTKDCMTKModelPrivate::RootType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateRootModel(parent);
-      res = d->RootModel->rowCount();
-      break;
-      break;
-    case qCTKDCMTKModelPrivate::PatientType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updatePatientModel(parent);
-      res = d->PatientModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::StudyType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateStudyModel(parent);
-      res = d->StudyModel->rowCount();
-      break;
-    case qCTKDCMTKModelPrivate::SeriesType:
-      const_cast<qCTKDCMTKModelPrivate*>(d)->updateSeriesModel(parent);
-      res = d->SeriesModel->rowCount();
-      break;
-    }
-  return res;
-}
-
-void qCTKDCMTKModel::setDataBase(const QString &db)
-{
-  QCTK_D(qCTKDCMTKModel);
-
-  this->beginResetModel();
-  d->DataBase.setDatabaseName(db);
-  
-  if (!d->DataBase.open() || d->DataBase.tables().empty())
-    {
-    //Q_ASSERT(d->DataBase.isOpen());
-    return;
-    }
-  this->endResetModel();
-  //this->m_DbPath = db;
-  //this->LoadStudies();
-}
-
-void qCTKDCMTKModel::rootRowsAboutToBeInserted(const QModelIndex& rootParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  QModelIndex index = this->createIndex(rootParent.row(), rootParent.column(), d->RootNode);
-  //this->beginInsertRows(index, start, end);
-}
-
-void qCTKDCMTKModel::rootRowsInserted(const QModelIndex& rootParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  //this->endInsertRows();
-}
-
-void qCTKDCMTKModel::patientRowsAboutToBeInserted(const QModelIndex& patientParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  QModelIndex index = this->createIndex(patientParent.row(), patientParent.column(), d->PatientNode);
-  //this->beginInsertRows(index, start, end);
-}
-
-void qCTKDCMTKModel::patientRowsInserted(const QModelIndex& patientParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  //this->endInsertRows();
-}
-
-void qCTKDCMTKModel::studyRowsAboutToBeInserted(const QModelIndex& studyParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  QModelIndex index = this->createIndex(studyParent.row(), studyParent.column(), d->StudyNode);
-  //this->beginInsertRows(index, start, end);
-}
-
-void qCTKDCMTKModel::studyRowsInserted(const QModelIndex& studyParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  //this->endInsertRows();
-}
-
-void qCTKDCMTKModel::seriesRowsAboutToBeInserted(const QModelIndex& seriesParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  QModelIndex index = this->createIndex(seriesParent.row(), seriesParent.column(), d->SeriesNode);
-  //this->beginInsertRows(index, start, end);
-}
-
-void qCTKDCMTKModel::seriesRowsInserted(const QModelIndex& seriesParent, int start, int end)
-{
-  QCTK_D(qCTKDCMTKModel);
-  //this->endInsertRows();
-}
-
-void qCTKDCMTKModel::onModelAboutToBeReset()
-{
-  //this->beginResetModel();
-}
-
-void qCTKDCMTKModel::onModelReset()
-{
-  //this->endResetModel();
-}
-
-void qCTKDCMTKModel::onLayoutAboutToBeChanged()
-{
-  //emit layoutAboutToBeChanged();
-}
-
-void qCTKDCMTKModel::onLayoutChanged()
-{
-  //emit layoutChanged();
-}
+#include <QStringList>
+#include <QSqlDriver>
+#include <QSqlError>
+#include <QSqlQuery>
+#include <QSqlQueryModel>
+#include <QSqlRecord>
+
+#include <QTime>
+#include <QDebug>
+
+#include "qCTKDCMTKModel.h"
+
+struct Node;
+
+class qCTKDCMTKModelPrivate:public qCTKPrivate<qCTKDCMTKModel>
+{
+public:
+  qCTKDCMTKModelPrivate();
+  ~qCTKDCMTKModelPrivate();
+  void init();
+
+  enum IndexType{
+    RootType,
+    PatientType,
+    StudyType,
+    SeriesType,
+    ImageType
+  };
+ 
+  void fetch(const QModelIndex& index, int limit);
+  Node* createNode(int row, int column, const QModelIndex& parent)const;
+  Node* nodeFromIndex(const QModelIndex& index)const;
+  QVariant value(const QModelIndex& index, int row, int field)const;
+  QString  generateQuery(const QString& fields, const QString& table, const QString& conditions = QString())const;
+  void updateQueries(Node* node)const;
+
+  Node*        RootNode;
+  QSqlDatabase DataBase;
+  QStringList  Headers;
+  QString      Sort;
+};
+
+struct Node
+{
+  ~Node()
+    {
+    foreach(Node* node, this->Children)
+      {
+      delete node;
+      }
+    this->Children.clear();
+    }
+  qCTKDCMTKModelPrivate::IndexType Type;
+  Node*     Parent;
+  QVector<Node*> Children;
+  int       Row;
+  int       Column;
+  QSqlQuery Query;
+  QString   UID;
+  int       RowCount;
+  bool      End;
+  bool      Fetching;
+};
+
+qCTKDCMTKModelPrivate::qCTKDCMTKModelPrivate()
+{
+  this->RootNode     = 0;
+}
+
+qCTKDCMTKModelPrivate::~qCTKDCMTKModelPrivate()
+{
+  delete this->RootNode;
+  this->RootNode = 0;
+}
+
+void qCTKDCMTKModelPrivate::init()
+{
+  QCTK_P(qCTKDCMTKModel);
+  this->Headers = QStringList() << "Name" << "Age" << "Scan" << "Date" << "Subject ID"
+                  << "Number" << "Institution" << "Referrer" << "Performer";
+}
+
+Node* qCTKDCMTKModelPrivate::nodeFromIndex(const QModelIndex& index)const
+{
+  return index.isValid() ? reinterpret_cast<Node*>(index.internalPointer()) : this->RootNode;
+}
+
+Node* qCTKDCMTKModelPrivate::createNode(int row, int column, const QModelIndex& parent)const
+{
+  QCTK_P(const qCTKDCMTKModel);
+  
+  Node* node = new Node;
+  Node* nodeParent = 0;
+  if (row == -1 || column == -1)
+    {// root node
+    node->Type = qCTKDCMTKModelPrivate::RootType;
+    node->Parent = 0;
+    }
+  else
+    {
+    nodeParent = this->nodeFromIndex(parent); 
+    nodeParent->Children.push_back(node);
+    node->Parent = (nodeParent == this->RootNode ? 0: nodeParent);
+    node->Type = qCTKDCMTKModelPrivate::IndexType(nodeParent->Type + 1);
+    }
+  node->Row = row;
+  node->Column = column;
+  if (node->Type != qCTKDCMTKModelPrivate::RootType)
+    {
+    int field = nodeParent->Query.record().indexOf("UID");
+    node->UID = this->value(parent, row, field).toString();
+    }
+  
+  node->RowCount = 0;
+  node->End = false;
+  node->Fetching = false;
+
+  this->updateQueries(node);
+  
+  return node;
+}
+
+QVariant qCTKDCMTKModelPrivate::value(const QModelIndex& parent, int row, int column) const
+{
+  Node* node = this->nodeFromIndex(parent);
+  if (row >= node->RowCount)
+    {      
+    const_cast<qCTKDCMTKModelPrivate *>(this)->fetch(parent, row + 256);
+    }
+
+  if (!node->Query.seek(row)) 
+    {
+    qDebug() << node->Query.lastError();
+    return QVariant();
+    }
+  return node->Query.value(column);
+}
+
+QString qCTKDCMTKModelPrivate::generateQuery(const QString& fields, const QString& table, const QString& conditions)const
+{
+  QString res = QString("SELECT ") + fields + QString(" FROM ") + table;
+  if (!conditions.isEmpty())
+    {
+    res += QString(" WHERE ") + conditions;
+    }
+  if (this->Sort.isEmpty())
+    {
+    res += QString(" ORDER BY ") + this->Sort;
+    }
+  return res;
+}
+
+void qCTKDCMTKModelPrivate::updateQueries(Node* node)const
+{
+  // are you kidding me, it should be virtualized here :-)
+  QString query;
+  switch(node->Type)
+    {
+    default:
+      Q_ASSERT(node->Type == qCTKDCMTKModelPrivate::RootType);
+      break;
+    case qCTKDCMTKModelPrivate::RootType:
+      //query = QString("SELECT  FROM ");
+      query = this->generateQuery("UID as UID, PatientsName as Name, PatientsAge as Age, PatientsBirthDate as Date, PatientID as 'Subject ID'","Patients");
+      break;
+    case qCTKDCMTKModelPrivate::PatientType:
+      //query = QString("SELECT  FROM Studies WHERE PatientsUID='%1'").arg(node->UID);
+      query = this->generateQuery("StudyInstanceUID as UID, StudyDescription as Name, ModalitiesInStudy as Scan, StudyDate as Date, AccessionNumber as Number, ReferringPhysician as Institution, ReferringPhysician as Referrer, PerformingPysiciansName as Performer", "Studies",QString("PatientsUID='%1'").arg(node->UID));
+      break;
+    case qCTKDCMTKModelPrivate::StudyType:
+      //query = QString("SELECT SeriesInstanceUID as UID, SeriesDescription as Name, BodyPartExamined as Scan, SeriesDate as Date, AcquisitionNumber as Number FROM Series WHERE StudyInstanceUID='%1'").arg(node->UID);
+      query = this->generateQuery("SeriesInstanceUID as UID, SeriesDescription as Name, BodyPartExamined as Scan, SeriesDate as Date, AcquisitionNumber as Number","Series",QString("StudyInstanceUID='%1'").arg(node->UID));
+      break;
+    case qCTKDCMTKModelPrivate::SeriesType:
+      //query = QString("SELECT Filename as UID, Filename as Name, SeriesInstanceUID as Date FROM Images WHERE SeriesInstanceUID='%1'").arg(node->UID);
+      query = this->generateQuery("Filename as UID, Filename as Name, SeriesInstanceUID as Date", "Images", QString("SeriesInstanceUID='%1'").arg(node->UID));
+      break;
+    case qCTKDCMTKModelPrivate::ImageType:
+      break;
+    }
+  node->Query = QSqlQuery(query, this->DataBase);
+  foreach(Node* child, node->Children)
+    {
+    this->updateQueries(child);
+    }
+}
+
+void qCTKDCMTKModelPrivate::fetch(const QModelIndex& index, int limit)
+{
+  QCTK_P(qCTKDCMTKModel);
+  Node* node = this->nodeFromIndex(index);
+  if (node->End || limit <= node->RowCount || node->Fetching/*|| bottom.column() == -1*/)
+    {
+    return;
+    }
+  node->Fetching = true;
+
+  int newRowCount;
+  const int oldRowCount = node->RowCount;
+
+  // try to seek directly
+  if (node->Query.seek(limit - 1)) 
+    {
+    newRowCount = limit;
+    } 
+  else 
+    {
+    newRowCount = qMax(oldRowCount, 1);
+    if (node->Query.seek(newRowCount - 1)) 
+      {
+      while (node->Query.next())
+        {
+        ++newRowCount;
+        }
+      } 
+    else 
+      {
+      // empty or invalid query
+      newRowCount = 0;
+      }
+    node->End = true; // this is the end.
+    }
+  if (newRowCount > 0 && newRowCount > node->RowCount) 
+    {
+    p->beginInsertRows(index, node->RowCount, newRowCount - 1);
+    node->RowCount = newRowCount;
+    node->Fetching = false;
+    p->endInsertRows();
+    } 
+  else 
+    {
+    node->RowCount = newRowCount;
+    node->Fetching = false;
+    }
+}
+
+qCTKDCMTKModel::qCTKDCMTKModel(QObject* parent)
+{
+  QCTK_INIT_PRIVATE(qCTKDCMTKModel);
+  qctk_d()->init();
+}
+
+qCTKDCMTKModel::~qCTKDCMTKModel()
+{
+}
+
+bool qCTKDCMTKModel::canFetchMore ( const QModelIndex & parent ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Node* node = d->nodeFromIndex(parent);
+  return !node->End;
+}
+
+int qCTKDCMTKModel::columnCount ( const QModelIndex & _parent ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Q_UNUSED(_parent);
+  return d->Headers.size();
+}
+
+QVariant qCTKDCMTKModel::data ( const QModelIndex & index, int role ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  if (role & ~(Qt::DisplayRole | Qt::EditRole))
+    {
+    return QVariant();
+    }
+  QModelIndex indexParent = this->parent(index);
+  Node* node = d->nodeFromIndex(indexParent);
+  Q_ASSERT(node->Row == indexParent.row());
+  if (index.row() >= node->RowCount)
+    {      
+    const_cast<qCTKDCMTKModelPrivate *>(d)->fetch(index, index.row());
+    }
+
+  if (!node->Query.seek(index.row())) 
+    {
+    qDebug() << node->Query.lastError();
+    return QVariant();
+    }
+  int field = node->Query.record().indexOf(d->Headers[index.column()]);
+  if (field < 0)
+    {
+    return QVariant();
+    }
+  return d->value(indexParent, index.row(), field);
+  //return node->Query.value(field);
+}
+
+void qCTKDCMTKModel::fetchMore ( const QModelIndex & parent )
+{
+  QCTK_D(qCTKDCMTKModel);
+  Node* node = d->nodeFromIndex(parent);
+  d->fetch(parent, qMax(node->RowCount, 0) + 256);
+}
+
+Qt::ItemFlags qCTKDCMTKModel::flags ( const QModelIndex & index ) const
+{
+  return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+bool qCTKDCMTKModel::hasChildren ( const QModelIndex & parent ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Node* node = d->nodeFromIndex(parent);
+  return node->RowCount > 0 || (!node->End && node->Query.seek(0));
+}
+
+QVariant qCTKDCMTKModel::headerData(int section, Qt::Orientation orientation, int role)const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  if (role & ~(Qt::DisplayRole | Qt::EditRole))
+    {
+    return QVariant();
+    }
+  if (orientation == Qt::Vertical)
+    {
+    return section;
+    }
+  Q_ASSERT(orientation == Qt::Horizontal);
+  Q_ASSERT(section < d->Headers.size());
+  return d->Headers[section];
+}
+
+QModelIndex qCTKDCMTKModel::index ( int row, int column, const QModelIndex & parent ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Node* parentNode = d->nodeFromIndex(parent);
+  Node* node = 0;
+  foreach(Node* tmpNode, parentNode->Children)
+    {
+    if (tmpNode->Row == row && 
+        tmpNode->Column == column)
+      {
+      node = tmpNode;
+      break;
+      }
+    }
+  if (node == 0)
+    {
+    node = d->createNode(row, column, parent);
+    }
+  return this->createIndex(row, column, node);
+}
+
+QModelIndex qCTKDCMTKModel::parent ( const QModelIndex & index ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Node* node = d->nodeFromIndex(index);
+  if (node == 0 || node->Parent == 0)
+    {
+    return QModelIndex();
+    }
+  return this->createIndex(node->Parent->Row, node->Parent->Column, node->Parent);
+}
+
+int qCTKDCMTKModel::rowCount ( const QModelIndex & parent ) const
+{
+  QCTK_D(const qCTKDCMTKModel);
+  Node* node = d->nodeFromIndex(parent);
+  if (node->RowCount == 0 && node->End)
+    {
+    const_cast<qCTKDCMTKModelPrivate*>(d)->fetch(parent, 256);
+    }
+  return node->RowCount;
+}
+
+void qCTKDCMTKModel::setDatabase(const QSqlDatabase &db)
+{
+  QCTK_D(qCTKDCMTKModel);
+
+  this->beginResetModel();
+  d->DataBase = db;
+  
+  delete d->RootNode;
+  d->RootNode = 0;
+
+  if (d->DataBase.tables().empty())
+    {
+    Q_ASSERT(d->DataBase.isOpen());
+    return;
+    }
+    
+  d->RootNode = d->createNode(-1, -1, QModelIndex());
+  
+  this->endResetModel();
+
+  bool hasQuerySize = d->RootNode->Query.driver()->hasFeature(QSqlDriver::QuerySize);
+  if (hasQuerySize && d->RootNode->Query.size() > 0) 
+    {
+    int newRowCount= d->RootNode->Query.size();
+    beginInsertRows(QModelIndex(), 0, qMax(0, newRowCount - 1));
+    d->RootNode->RowCount = newRowCount;
+    d->RootNode->End = true;
+    endInsertRows();
+    } 
+  else
+    {
+    d->RootNode->RowCount = 0;
+    }
+  d->fetch(QModelIndex(), 256);
+}
+
+void qCTKDCMTKModel::sort(int column, Qt::SortOrder order)
+{
+  QCTK_D(qCTKDCMTKModel);
+  emit layoutAboutToBeChanged();
+  d->Sort = QString("'%1' %2")
+    .arg(d->Headers[column])
+    .arg(order == Qt::AscendingOrder ? "ASC" : "DESC");
+  d->updateQueries(d->RootNode);
+  emit layoutChanged();
+}
+
+bool qCTKDCMTKModel::setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role)
+{
+  QCTK_D(qCTKDCMTKModel);
+  if (role & ~(Qt::DisplayRole | Qt::EditRole))
+    {
+    return false;
+    }
+  if (orientation == Qt::Vertical)
+    {
+    return false;
+    }
+  if (value.toString() == d->Headers[section])
+    {
+    return false;
+    }
+  d->Headers[section] = value.toString();
+  emit this->headerDataChanged(orientation, section, section);
+  return true;
+}

+ 5 - 16
Libs/DICOM/Core/qCTKDCMTKModel.h

@@ -3,6 +3,7 @@
 
 // QT includes 
 #include <QAbstractItemModel>
+#include <QSqlDatabase>
 
 // qCTK includes
 #include <ctkPimpl.h>
@@ -17,7 +18,7 @@ public:
   explicit qCTKDCMTKModel(QObject* parent = 0);
   virtual ~qCTKDCMTKModel();
 
-  void setDataBase(const QString& database);
+  void setDatabase(const QSqlDatabase& dataBase);
 
   virtual bool canFetchMore ( const QModelIndex & parent ) const;
   virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
@@ -25,24 +26,12 @@ public:
   virtual void fetchMore ( const QModelIndex & parent );
   virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;
   virtual bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
-  //virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
+  virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole)const;
   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 setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole );
-protected slots:
-  void rootRowsAboutToBeInserted(const QModelIndex& rootParent, int start, int end);
-  void rootRowsInserted(const QModelIndex& rootParent, int start, int end);
-  void patientRowsAboutToBeInserted(const QModelIndex& patientParent, int start, int end);
-  void patientRowsInserted(const QModelIndex& patientParent, int start, int end);
-  void studyRowsAboutToBeInserted(const QModelIndex& studyParent, int start, int end);
-  void studyRowsInserted(const QModelIndex& studyParent, int start, int end);
-  void seriesRowsAboutToBeInserted(const QModelIndex& seriesParent, int start, int end);
-  void seriesRowsInserted(const QModelIndex& seriesParent, int start, int end);
-  void onModelAboutToBeReset();
-  void onModelReset();
-  void onLayoutAboutToBeChanged();
-  void onLayoutChanged();
+  virtual bool setHeaderData ( int section, Qt::Orientation orientation, const QVariant & value, int role = Qt::EditRole );
+  virtual void qCTKDCMTKModel::sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
 
 private:
   QCTK_DECLARE_PRIVATE(qCTKDCMTKModel);