|
@@ -80,6 +80,11 @@ public:
|
|
|
bool loggedExec(QSqlQuery& query);
|
|
|
bool loggedExec(QSqlQuery& query, const QString& queryString);
|
|
|
|
|
|
+ // dataset must be set always
|
|
|
+ // filePath has to be set if this is an import of an actual file
|
|
|
+ void insert ( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile = true, bool generateThumbnail = true);
|
|
|
+
|
|
|
+
|
|
|
/// Name of the database file (i.e. for SQLITE the sqlite file)
|
|
|
QString DatabaseFileName;
|
|
|
QString LastError;
|
|
@@ -449,10 +454,47 @@ void ctkDICOMDatabase::insert( DcmDataset *dataset, bool storeFile, bool generat
|
|
|
ctkDataset.InitializeFromDataset(dataset);
|
|
|
this->insert(ctkDataset,storeFile,generateThumbnail);
|
|
|
}
|
|
|
-
|
|
|
void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile, bool generateThumbnail)
|
|
|
{
|
|
|
Q_D(ctkDICOMDatabase);
|
|
|
+ d->insert(ctkDataset, QString(), storeFile, generateThumbnail);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMDatabase::insert ( const QString& filePath, bool storeFile, bool generateThumbnail, bool createHierarchy, const QString& destinationDirectoryName)
|
|
|
+{
|
|
|
+ Q_D(ctkDICOMDatabase);
|
|
|
+
|
|
|
+ /// first we check if the file is already in the database
|
|
|
+ if (fileExistsAndUpToDate(filePath))
|
|
|
+ {
|
|
|
+ logger.debug( "File " + filePath + " already added.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.debug( "Processing " + filePath );
|
|
|
+
|
|
|
+ std::string filename = filePath.toStdString();
|
|
|
+
|
|
|
+ DcmFileFormat fileformat;
|
|
|
+ ctkDICOMDataset ctkDataset;
|
|
|
+
|
|
|
+ ctkDataset.InitializeFromFile(filePath);
|
|
|
+ if ( ctkDataset.IsInitialized() )
|
|
|
+ {
|
|
|
+ d->insert( ctkDataset, filePath, storeFile, generateThumbnail );
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ logger.warn(QString("Could not read DICOM file:") + filePath);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//------------------------------------------------------------------------------
|
|
|
+void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile, bool generateThumbnail)
|
|
|
+{
|
|
|
+ Q_Q(ctkDICOMDatabase);
|
|
|
|
|
|
// Check to see if the file has already been loaded
|
|
|
// TODO:
|
|
@@ -462,7 +504,7 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
|
|
|
QString sopInstanceUID ( ctkDataset.GetElementAsString(DCM_SOPInstanceUID) );
|
|
|
|
|
|
- QSqlQuery fileExists ( d->Database );
|
|
|
+ QSqlQuery fileExists ( Database );
|
|
|
fileExists.prepare("SELECT InsertTimestamp,Filename FROM Images WHERE SOPInstanceUID == ?");
|
|
|
fileExists.bindValue(0,sopInstanceUID);
|
|
|
fileExists.exec();
|
|
@@ -515,25 +557,37 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
// TODO: if we are called from insert(file) we
|
|
|
// have to do something else
|
|
|
//
|
|
|
- QString filename;
|
|
|
- if ( storeFile && !this->isInMemory() )
|
|
|
+ QString filename = filePath;
|
|
|
+ if ( storeFile && !q->isInMemory() )
|
|
|
{
|
|
|
-
|
|
|
- QString destinationDirectoryName = databaseDirectory() + "/dicom/";
|
|
|
+ // QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID;
|
|
|
+ QString destinationDirectoryName = q->databaseDirectory() + "/dicom/";
|
|
|
QDir destinationDir(destinationDirectoryName);
|
|
|
- QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID;
|
|
|
- destinationDir.mkpath(studySeriesDirectory);
|
|
|
+ filename = destinationDirectoryName + q->pathForDataset(ctkDataset);
|
|
|
+ destinationDir.mkpath(QFileInfo(q->pathForDataset(ctkDataset)).dir().canonicalPath());
|
|
|
|
|
|
- filename = databaseDirectory() + "/dicom/" + pathForDataset(ctkDataset);
|
|
|
- logger.debug ( "Saving file: " + filename );
|
|
|
- if ( !ctkDataset.SaveToFile( filename) )
|
|
|
+ if(filePath.isEmpty())
|
|
|
{
|
|
|
- logger.error ( "Error saving file: " + filename );
|
|
|
- return;
|
|
|
+ logger.debug ( "Saving file: " + filename );
|
|
|
+
|
|
|
+ if ( !ctkDataset.SaveToFile( filename) )
|
|
|
+ {
|
|
|
+ logger.error ( "Error saving file: " + filename );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // we're inserting an existing file
|
|
|
+
|
|
|
+ QFile currentFile( filePath );
|
|
|
+ currentFile.copy(filename);
|
|
|
+ logger.debug( "Copy file from: " + filePath );
|
|
|
+ logger.debug( "Copy file to : " + filename );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- QSqlQuery checkPatientExistsQuery(d->Database);
|
|
|
+ QSqlQuery checkPatientExistsQuery(Database);
|
|
|
//The dbPatientID is a unique number within the database, generated by the sqlite autoincrement
|
|
|
//The patientID is the (non-unique) DICOM patient id
|
|
|
int dbPatientID = -1;
|
|
@@ -541,7 +595,7 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
if ( patientID != "" && patientsName != "" )
|
|
|
{
|
|
|
//Speed up: Check if patient is the same as in last file; very probable, as all images belonging to a study have the same patient
|
|
|
- if( d->lastPatientID != patientID || d->lastPatientsBirthDate != patientsBirthDate || d->lastPatientsName != patientsName )
|
|
|
+ if( lastPatientID != patientID || lastPatientsBirthDate != patientsBirthDate || lastPatientsName != patientsName )
|
|
|
{
|
|
|
// Ok, something is different from last insert, let's insert him if he's not
|
|
|
// already in the db.
|
|
@@ -552,7 +606,7 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
checkPatientExistsQuery.prepare ( "SELECT * FROM Patients WHERE PatientID = ? AND PatientsName = ?" );
|
|
|
checkPatientExistsQuery.bindValue ( 0, patientID );
|
|
|
checkPatientExistsQuery.bindValue ( 1, patientsName );
|
|
|
- d->loggedExec(checkPatientExistsQuery);
|
|
|
+ loggedExec(checkPatientExistsQuery);
|
|
|
|
|
|
if (checkPatientExistsQuery.next())
|
|
|
{
|
|
@@ -562,7 +616,7 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
else
|
|
|
{
|
|
|
// Insert it
|
|
|
- QSqlQuery insertPatientStatement ( d->Database );
|
|
|
+ QSqlQuery insertPatientStatement ( Database );
|
|
|
insertPatientStatement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
insertPatientStatement.bindValue ( 0, patientsName );
|
|
|
insertPatientStatement.bindValue ( 1, patientID );
|
|
@@ -572,29 +626,29 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
// TODO: shift patient's age to study, since this is not a patient level attribute in images
|
|
|
// insertPatientStatement.bindValue ( 5, patientsAge );
|
|
|
insertPatientStatement.bindValue ( 6, patientComments );
|
|
|
- d->loggedExec(insertPatientStatement);
|
|
|
+ loggedExec(insertPatientStatement);
|
|
|
dbPatientID = insertPatientStatement.lastInsertId().toInt();
|
|
|
logger.debug ( "New patient inserted: " + QString().setNum ( dbPatientID ) );
|
|
|
|
|
|
}
|
|
|
/// keep this for the next image
|
|
|
- d->lastPatientUID = dbPatientID;
|
|
|
- d->lastPatientID = patientID;
|
|
|
- d->lastPatientsBirthDate = patientsBirthDate;
|
|
|
- d->lastPatientsName = patientsName;
|
|
|
+ lastPatientUID = dbPatientID;
|
|
|
+ lastPatientID = patientID;
|
|
|
+ lastPatientsBirthDate = patientsBirthDate;
|
|
|
+ lastPatientsName = patientsName;
|
|
|
}
|
|
|
|
|
|
// Patient is in now. Let's continue with the study
|
|
|
|
|
|
- if ( studyInstanceUID != "" && d->lastStudyInstanceUID != studyInstanceUID )
|
|
|
+ if ( studyInstanceUID != "" && lastStudyInstanceUID != studyInstanceUID )
|
|
|
{
|
|
|
- QSqlQuery checkStudyExistsQuery (d->Database);
|
|
|
+ QSqlQuery checkStudyExistsQuery (Database);
|
|
|
checkStudyExistsQuery.prepare ( "SELECT * FROM Studies WHERE StudyInstanceUID = ?" );
|
|
|
checkStudyExistsQuery.bindValue ( 0, studyInstanceUID );
|
|
|
checkStudyExistsQuery.exec();
|
|
|
if(!checkStudyExistsQuery.next())
|
|
|
{
|
|
|
- QSqlQuery insertStudyStatement ( d->Database );
|
|
|
+ QSqlQuery insertStudyStatement ( Database );
|
|
|
insertStudyStatement.prepare ( "INSERT INTO Studies ( 'StudyInstanceUID', 'PatientsUID', 'StudyID', 'StudyDate', 'StudyTime', 'AccessionNumber', 'ModalitiesInStudy', 'InstitutionName', 'ReferringPhysician', 'PerformingPhysiciansName', 'StudyDescription' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
insertStudyStatement.bindValue ( 0, studyInstanceUID );
|
|
|
insertStudyStatement.bindValue ( 1, dbPatientID );
|
|
@@ -613,22 +667,22 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- d->lastStudyInstanceUID = studyInstanceUID;
|
|
|
+ lastStudyInstanceUID = studyInstanceUID;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if ( seriesInstanceUID != "" && seriesInstanceUID != d->lastSeriesInstanceUID )
|
|
|
+ if ( seriesInstanceUID != "" && seriesInstanceUID != lastSeriesInstanceUID )
|
|
|
{
|
|
|
- QSqlQuery checkSeriesExistsQuery (d->Database);
|
|
|
+ QSqlQuery checkSeriesExistsQuery (Database);
|
|
|
checkSeriesExistsQuery.prepare ( "SELECT * FROM Series WHERE SeriesInstanceUID = ?" );
|
|
|
checkSeriesExistsQuery.bindValue ( 0, seriesInstanceUID );
|
|
|
logger.warn ( "Statement: " + checkSeriesExistsQuery.lastQuery() );
|
|
|
- d->loggedExec(checkSeriesExistsQuery);
|
|
|
+ loggedExec(checkSeriesExistsQuery);
|
|
|
if(!checkSeriesExistsQuery.next())
|
|
|
{
|
|
|
- QSqlQuery insertSeriesStatement ( d->Database );
|
|
|
+ QSqlQuery insertSeriesStatement ( Database );
|
|
|
insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
|
|
|
insertSeriesStatement.bindValue ( 0, seriesInstanceUID );
|
|
|
insertSeriesStatement.bindValue ( 1, studyInstanceUID );
|
|
@@ -646,11 +700,11 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
if ( !insertSeriesStatement.exec() )
|
|
|
{
|
|
|
logger.error ( "Error executing statament: " + insertSeriesStatement.lastQuery() + " Error: " + insertSeriesStatement.lastError().text() );
|
|
|
- d->lastSeriesInstanceUID = "";
|
|
|
+ lastSeriesInstanceUID = "";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- d->lastSeriesInstanceUID = seriesInstanceUID;
|
|
|
+ lastSeriesInstanceUID = seriesInstanceUID;
|
|
|
}
|
|
|
|
|
|
}
|
|
@@ -659,13 +713,13 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
//
|
|
|
if ( !filename.isEmpty() )
|
|
|
{
|
|
|
- QSqlQuery checkImageExistsQuery (d->Database);
|
|
|
+ QSqlQuery checkImageExistsQuery (Database);
|
|
|
checkImageExistsQuery.prepare ( "SELECT * FROM Images WHERE Filename = ?" );
|
|
|
checkImageExistsQuery.bindValue ( 0, filename );
|
|
|
checkImageExistsQuery.exec();
|
|
|
if(!checkImageExistsQuery.next())
|
|
|
{
|
|
|
- QSqlQuery insertImageStatement ( d->Database );
|
|
|
+ QSqlQuery insertImageStatement ( Database );
|
|
|
insertImageStatement.prepare ( "INSERT INTO Images ( 'SOPInstanceUID', 'Filename', 'SeriesInstanceUID', 'InsertTimestamp' ) VALUES ( ?, ?, ?, ? )" );
|
|
|
insertImageStatement.bindValue ( 0, sopInstanceUID );
|
|
|
insertImageStatement.bindValue ( 1, filename );
|
|
@@ -705,61 +759,31 @@ void ctkDICOMDatabase::insert( const ctkDICOMDataset& ctkDataset, bool storeFile
|
|
|
*/
|
|
|
|
|
|
if(generateThumbnail){
|
|
|
- if(d->thumbnailGenerator)
|
|
|
+ if(thumbnailGenerator)
|
|
|
{
|
|
|
QString studySeriesDirectory = studyInstanceUID + "/" + seriesInstanceUID;
|
|
|
//Create thumbnail here
|
|
|
- QString thumbnailPath = databaseDirectory() +
|
|
|
- "/thumbs/" + this->pathForDataset(ctkDataset) + ".png";
|
|
|
+ QString thumbnailPath = q->databaseDirectory() +
|
|
|
+ "/thumbs/" + q->pathForDataset(ctkDataset) + ".png";
|
|
|
//studyInstanceUID + "/" +
|
|
|
//seriesInstanceUID + "/" +
|
|
|
//sopInstanceUID + ".png";
|
|
|
QFileInfo thumbnailInfo(thumbnailPath);
|
|
|
if(!(thumbnailInfo.exists() && (thumbnailInfo.lastModified() > QFileInfo(filename).lastModified()))){
|
|
|
- QDir(databaseDirectory() + "/thumbs/").mkpath(studySeriesDirectory);
|
|
|
+ QDir(q->databaseDirectory() + "/thumbs/").mkpath(studySeriesDirectory);
|
|
|
DicomImage dcmImage(QDir::toNativeSeparators(filename).toAscii());
|
|
|
- d->thumbnailGenerator->generateThumbnail(&dcmImage, thumbnailPath);
|
|
|
+ thumbnailGenerator->generateThumbnail(&dcmImage, thumbnailPath);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (isInMemory())
|
|
|
+ if (q->isInMemory())
|
|
|
{
|
|
|
- emit databaseChanged();
|
|
|
+ emit q->databaseChanged();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-//------------------------------------------------------------------------------
|
|
|
-void ctkDICOMDatabase::insert ( const QString& filePath, bool storeFile, bool generateThumbnail, bool createHierarchy, const QString& destinationDirectoryName)
|
|
|
-{
|
|
|
-
|
|
|
- /// first we check if the file is already in the database
|
|
|
- if (fileExistsAndUpToDate(filePath))
|
|
|
- {
|
|
|
- logger.debug( "File " + filePath + " already added.");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- logger.debug( "Processing " + filePath );
|
|
|
-
|
|
|
- std::string filename = filePath.toStdString();
|
|
|
-
|
|
|
- DcmFileFormat fileformat;
|
|
|
- ctkDICOMDataset ctkDataset;
|
|
|
-
|
|
|
- ctkDataset.InitializeFromFile(filePath);
|
|
|
- if ( ctkDataset.IsInitialized() )
|
|
|
- {
|
|
|
- this->insert( ctkDataset, storeFile, generateThumbnail );
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- logger.warn(QString("Could not read DICOM file:") + filePath);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
bool ctkDICOMDatabase::fileExistsAndUpToDate(const QString& filePath)
|
|
|
{
|
|
|
Q_D(ctkDICOMDatabase);
|