|
@@ -18,6 +18,8 @@
|
|
|
|
|
|
=========================================================================*/
|
|
|
|
|
|
+#include <stdexcept>
|
|
|
+
|
|
|
// Qt includes
|
|
|
#include <QSqlQuery>
|
|
|
#include <QSqlRecord>
|
|
@@ -56,19 +58,35 @@ static ctkLogger logger("org.commontk.dicom.DICOMDatabase" );
|
|
|
//------------------------------------------------------------------------------
|
|
|
class ctkDICOMDatabasePrivate
|
|
|
{
|
|
|
+ Q_DECLARE_PUBLIC(ctkDICOMDatabase);
|
|
|
+protected:
|
|
|
+ ctkDICOMDatabase* const q_ptr;
|
|
|
+
|
|
|
public:
|
|
|
- ctkDICOMDatabasePrivate();
|
|
|
+ ctkDICOMDatabasePrivate(ctkDICOMDatabase&);
|
|
|
~ctkDICOMDatabasePrivate();
|
|
|
- QSqlDatabase db;
|
|
|
+ void init(QString databaseFile);
|
|
|
+ bool executeScript(const QString script);
|
|
|
|
|
|
+ QString DatabaseFileName;
|
|
|
+ QString LastError;
|
|
|
+ QSqlDatabase Database;
|
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
// ctkDICOMDatabasePrivate methods
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
-ctkDICOMDatabasePrivate::ctkDICOMDatabasePrivate()
|
|
|
+ctkDICOMDatabasePrivate::ctkDICOMDatabasePrivate(ctkDICOMDatabase& o): q_ptr(&o)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMDatabasePrivate::init(QString databaseFilename)
|
|
|
{
|
|
|
+ Q_Q(ctkDICOMDatabase);
|
|
|
+ q->openDatabase(databaseFilename);
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
@@ -77,11 +95,37 @@ ctkDICOMDatabasePrivate::~ctkDICOMDatabasePrivate()
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMDatabase::openDatabase(const QString databaseFile)
|
|
|
+{
|
|
|
+ Q_D(ctkDICOMDatabase);
|
|
|
+ d->Database = QSqlDatabase::addDatabase("QSQLITE","DICOM-DB");
|
|
|
+ d->Database.setDatabaseName(databaseFile);
|
|
|
+ if ( ! (d->Database.open()) )
|
|
|
+ {
|
|
|
+ d->LastError = d->Database.lastError().text();
|
|
|
+ throw std::runtime_error(qPrintable(d->LastError));
|
|
|
+ }
|
|
|
+ if ( d->Database.tables().empty() )
|
|
|
+ {
|
|
|
+ initializeDatabase();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
// ctkDICOMDatabase methods
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
+ctkDICOMDatabase::ctkDICOMDatabase(QString databaseFile)
|
|
|
+ : d_ptr(new ctkDICOMDatabasePrivate(*this))
|
|
|
+{
|
|
|
+ Q_D(ctkDICOMDatabase);
|
|
|
+ d->init(databaseFile);
|
|
|
+}
|
|
|
+
|
|
|
ctkDICOMDatabase::ctkDICOMDatabase()
|
|
|
- : d_ptr(new ctkDICOMDatabasePrivate)
|
|
|
+ : d_ptr(new ctkDICOMDatabasePrivate(*this))
|
|
|
{
|
|
|
}
|
|
|
|
|
@@ -90,16 +134,67 @@ ctkDICOMDatabase::~ctkDICOMDatabase()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
+//----------------------------------------------------------------------------
|
|
|
+
|
|
|
//------------------------------------------------------------------------------
|
|
|
-void ctkDICOMDatabase::setDatabase ( QSqlDatabase database ) {
|
|
|
- Q_D(ctkDICOMDatabase);
|
|
|
- d->db = database;
|
|
|
+const QString& ctkDICOMDatabase::GetLastError() const {
|
|
|
+ Q_D(const ctkDICOMDatabase);
|
|
|
+ return d->LastError;
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
-const QSqlDatabase& ctkDICOMDatabase::database () const {
|
|
|
+const QSqlDatabase& ctkDICOMDatabase::database() const {
|
|
|
Q_D(const ctkDICOMDatabase);
|
|
|
- return d->db;
|
|
|
+ return d->Database;
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+bool ctkDICOMDatabasePrivate::executeScript(const QString script) {
|
|
|
+ QFile scriptFile(script);
|
|
|
+ scriptFile.open(QIODevice::ReadOnly);
|
|
|
+ if ( !scriptFile.isOpen() )
|
|
|
+ {
|
|
|
+ qDebug() << "Script file " << script << " could not be opened!\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ QString sqlCommands( QTextStream(&scriptFile).readAll() );
|
|
|
+ sqlCommands.replace( '\n', ' ' );
|
|
|
+ sqlCommands.replace("; ", ";\n");
|
|
|
+
|
|
|
+ QStringList sqlCommandsLines = sqlCommands.split('\n');
|
|
|
+
|
|
|
+ QSqlQuery query(Database);
|
|
|
+
|
|
|
+ for (QStringList::iterator it = sqlCommandsLines.begin(); it != sqlCommandsLines.end()-1; ++it)
|
|
|
+ {
|
|
|
+ if (! (*it).startsWith("--") )
|
|
|
+ {
|
|
|
+ qDebug() << *it << "\n";
|
|
|
+ query.exec(*it);
|
|
|
+ if (query.lastError().type())
|
|
|
+ {
|
|
|
+ qDebug() << "There was an error during execution of the statement: " << (*it);
|
|
|
+ qDebug() << "Error message: " << query.lastError().text();
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+bool ctkDICOMDatabase::initializeDatabase(const char* sqlFileName)
|
|
|
+{
|
|
|
+ Q_D(ctkDICOMDatabase);
|
|
|
+ return d->executeScript(sqlFileName);
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMDatabase::closeDatabase()
|
|
|
+{
|
|
|
+ Q_D(ctkDICOMDatabase);
|
|
|
+ d->Database.close();
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
@@ -112,7 +207,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
Q_D(ctkDICOMDatabase);
|
|
|
|
|
|
// Check to see if the file has already been loaded
|
|
|
- QSqlQuery fileExists ( d->db );
|
|
|
+ QSqlQuery fileExists ( d->Database );
|
|
|
fileExists.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?");
|
|
|
fileExists.bindValue(0,filename);
|
|
|
fileExists.exec();
|
|
@@ -169,7 +264,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
dataset->findAndGetSint32(DCM_EchoNumbers, echoNumber);
|
|
|
dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
|
|
|
|
|
|
- QSqlQuery check_exists_query(d->db);
|
|
|
+ QSqlQuery check_exists_query(d->Database);
|
|
|
//The patient UID is a unique number within the database, generated by the sqlite autoincrement
|
|
|
int patientUID = -1;
|
|
|
if ( patientID != "" && patientsName != "" )
|
|
@@ -187,7 +282,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
else
|
|
|
{
|
|
|
// Insert it
|
|
|
- QSqlQuery statement ( d->db );
|
|
|
+ QSqlQuery statement ( d->Database );
|
|
|
statement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
statement.bindValue ( 0, QString ( patientsName.c_str() ) );
|
|
|
statement.bindValue ( 1, QString ( patientID.c_str() ) );
|
|
@@ -209,7 +304,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
check_exists_query.exec();
|
|
|
if(!check_exists_query.next())
|
|
|
{
|
|
|
- QSqlQuery statement ( d->db );
|
|
|
+ QSqlQuery statement ( d->Database );
|
|
|
statement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
statement.bindValue ( 0, QString ( studyInstanceUID.c_str() ) );
|
|
|
statement.bindValue ( 1, patientUID );
|
|
@@ -237,7 +332,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
check_exists_query.exec();
|
|
|
if(!check_exists_query.next())
|
|
|
{
|
|
|
- QSqlQuery statement ( d->db );
|
|
|
+ QSqlQuery statement ( d->Database );
|
|
|
statement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
statement.bindValue ( 0, QString ( seriesInstanceUID.c_str() ) );
|
|
|
statement.bindValue ( 1, QString ( studyInstanceUID.c_str() ) );
|
|
@@ -265,7 +360,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, QString filename ) {
|
|
|
check_exists_query.exec();
|
|
|
if(!check_exists_query.next())
|
|
|
{
|
|
|
- QSqlQuery statement ( d->db );
|
|
|
+ QSqlQuery statement ( d->Database );
|
|
|
statement.prepare ( "INSERT INTO Images ( 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ? )" );
|
|
|
statement.bindValue ( 0, filename );
|
|
|
statement.bindValue ( 1, QString ( seriesInstanceUID.c_str() ) );
|