123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- #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;
- }
|