ctkDICOMIndexer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QSqlQuery>
  16. #include <QSqlRecord>
  17. #include <QSqlError>
  18. #include <QVariant>
  19. #include <QDate>
  20. #include <QStringList>
  21. #include <QSet>
  22. #include <QFile>
  23. #include <QDirIterator>
  24. #include <QFileInfo>
  25. #include <QDebug>
  26. #include <QPixmap>
  27. // ctkDICOM includes
  28. #include "ctkLogger.h"
  29. #include "ctkDICOMIndexer.h"
  30. #include "ctkDICOMAbstractThumbnailGenerator.h"
  31. // DCMTK includes
  32. #include <dcmtk/dcmdata/dcfilefo.h>
  33. #include <dcmtk/dcmdata/dcfilefo.h>
  34. #include <dcmtk/dcmdata/dcdeftag.h>
  35. #include <dcmtk/dcmdata/dcdatset.h>
  36. #include <dcmtk/ofstd/ofcond.h>
  37. #include <dcmtk/ofstd/ofstring.h>
  38. #include <dcmtk/ofstd/ofstd.h> /* for class OFStandard */
  39. #include <dcmtk/dcmdata/dcddirif.h> /* for class DicomDirInterface */
  40. #include <dcmtk/dcmimgle/dcmimage.h> /* for class DicomImage */
  41. #include <dcmtk/dcmimage/diregist.h> /* include support for color images */
  42. //------------------------------------------------------------------------------
  43. static ctkLogger logger("org.commontk.dicom.DICOMIndexer" );
  44. //------------------------------------------------------------------------------
  45. //------------------------------------------------------------------------------
  46. class ctkDICOMIndexerPrivate
  47. {
  48. public:
  49. ctkDICOMIndexerPrivate();
  50. ~ctkDICOMIndexerPrivate();
  51. ctkDICOMAbstractThumbnailGenerator* thumbnailGenerator;
  52. /// these are for optimizing the import of image sequences
  53. /// since most information are identical for all slices
  54. OFString lastPatientID;
  55. OFString lastPatientsName;
  56. OFString lastPatientsBirthDate;
  57. OFString lastStudyInstanceUID;
  58. OFString lastSeriesInstanceUID;
  59. int lastPatientUID;
  60. };
  61. //------------------------------------------------------------------------------
  62. // ctkDICOMIndexerPrivate methods
  63. //------------------------------------------------------------------------------
  64. ctkDICOMIndexerPrivate::ctkDICOMIndexerPrivate()
  65. {
  66. this->thumbnailGenerator = NULL;
  67. this->lastPatientID = "";
  68. this->lastPatientsName = "";
  69. this->lastPatientsBirthDate = "";
  70. this->lastStudyInstanceUID = "";
  71. this->lastSeriesInstanceUID = "";
  72. this->lastPatientUID = -1;
  73. }
  74. //------------------------------------------------------------------------------
  75. ctkDICOMIndexerPrivate::~ctkDICOMIndexerPrivate()
  76. {
  77. }
  78. //------------------------------------------------------------------------------
  79. //------------------------------------------------------------------------------
  80. // ctkDICOMIndexer methods
  81. //------------------------------------------------------------------------------
  82. ctkDICOMIndexer::ctkDICOMIndexer(QObject *parent):d_ptr(new ctkDICOMIndexerPrivate)
  83. {
  84. Q_UNUSED(parent);
  85. }
  86. //------------------------------------------------------------------------------
  87. ctkDICOMIndexer::~ctkDICOMIndexer()
  88. {
  89. }
  90. //------------------------------------------------------------------------------
  91. bool ctkDICOMIndexer::loggedExec(QSqlQuery& query)
  92. {
  93. return (this->loggedExec(query, QString("")));
  94. }
  95. //------------------------------------------------------------------------------
  96. bool ctkDICOMIndexer::loggedExec(QSqlQuery& query, const QString& queryString)
  97. {
  98. bool success;
  99. if (queryString.compare(""))
  100. {
  101. success = query.exec(queryString);
  102. }
  103. else
  104. {
  105. success = query.exec();
  106. }
  107. if (!success)
  108. {
  109. QSqlError sqlError = query.lastError();
  110. logger.debug( "SQL failed\n Bad SQL: " + query.lastQuery());
  111. logger.debug( "Error text: " + sqlError.text());
  112. }
  113. else
  114. {
  115. logger.debug( "SQL worked!\n SQL: " + query.lastQuery());
  116. }
  117. return (success);
  118. }
  119. //------------------------------------------------------------------------------
  120. void ctkDICOMIndexer::addFile(ctkDICOMDatabase& ctkDICOMDatabase,
  121. const QString& filePath,
  122. const QString& destinationDirectoryName,
  123. bool createHierarchy,
  124. bool createThumbnails)
  125. {
  126. Q_D(ctkDICOMIndexer);
  127. logger.setDebug();
  128. DcmFileFormat fileformat;
  129. DcmDataset *dataset;
  130. std::string filename = filePath.toStdString();
  131. emit indexingFilePath(filePath);
  132. /// first we check if the file is already in the database
  133. QSqlQuery check_filename_query(ctkDICOMDatabase.database());
  134. check_filename_query.prepare("SELECT InsertTimestamp FROM Images WHERE Filename == ?");
  135. check_filename_query.bindValue(0,filePath);
  136. this->loggedExec(check_filename_query);
  137. if (
  138. check_filename_query.next() &&
  139. QFileInfo(filePath).lastModified() < QDateTime::fromString(check_filename_query.value(0).toString(),Qt::ISODate)
  140. )
  141. {
  142. logger.debug( "File " + filePath + " already added.");
  143. return;
  144. }
  145. check_filename_query.finish();
  146. logger.debug( "Processing " + filePath );
  147. OFCondition status = fileformat.loadFile(filename.c_str());
  148. dataset = fileformat.getDataset();
  149. if (!status.good())
  150. {
  151. logger.error( "Could not load " + filePath );
  152. logger.error( "DCMTK says: " + QString(status.text()) );
  153. return;
  154. }
  155. OFString patientsName, patientID, patientsBirthDate, patientsBirthTime, patientsSex,
  156. patientComments, patientsAge;
  157. OFString studyInstanceUID, studyID, studyDate, studyTime,
  158. accessionNumber, modalitiesInStudy, institutionName, performingPhysiciansName, referringPhysician, studyDescription;
  159. OFString seriesInstanceUID, seriesDate, seriesTime,
  160. seriesDescription, bodyPartExamined, frameOfReferenceUID,
  161. contrastAgent, scanningSequence;
  162. OFString instanceNumber, sopInstanceUID ;
  163. Sint32 seriesNumber = 0, acquisitionNumber = 0, echoNumber = 0, temporalPosition = 0;
  164. //The patient UID is a unique number within the database, generated by the sqlite autoincrement
  165. //Thus, this is _not_ the DICOM Patient ID.
  166. int patientUID = -1;
  167. //If the following fields can not be evaluated, cancel evaluation of the DICOM file
  168. if (!dataset->findAndGetOFString(DCM_PatientName, patientsName).good())
  169. {
  170. logger.error( "Could not read DCM_PatientName from " + filePath );
  171. return;
  172. }
  173. if (!dataset->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID).good())
  174. {
  175. logger.error( "Could not read DCM_StudyInstanceUID from " + filePath );
  176. return;
  177. }
  178. if (!dataset->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID).good())
  179. {
  180. logger.error( "Could not read DCM_SeriesInstanceUID from " + filePath );
  181. return;
  182. }
  183. if (!dataset->findAndGetOFString(DCM_SOPInstanceUID, sopInstanceUID).good())
  184. {
  185. logger.error( "Could not read DCM_SOPInstanceUID from " + filePath );
  186. return;
  187. }
  188. if (!dataset->findAndGetOFString(DCM_InstanceNumber, instanceNumber).good())
  189. {
  190. logger.error( "Could not read DCM_InstanceNumber from " + filePath );
  191. return;
  192. }
  193. dataset->findAndGetOFString(DCM_PatientID, patientID);
  194. dataset->findAndGetOFString(DCM_PatientBirthDate, patientsBirthDate);
  195. dataset->findAndGetOFString(DCM_PatientBirthTime, patientsBirthTime);
  196. dataset->findAndGetOFString(DCM_PatientSex, patientsSex);
  197. dataset->findAndGetOFString(DCM_PatientAge, patientsAge);
  198. dataset->findAndGetOFString(DCM_PatientComments, patientComments);
  199. dataset->findAndGetOFString(DCM_StudyID, studyID);
  200. dataset->findAndGetOFString(DCM_StudyDate, studyDate);
  201. dataset->findAndGetOFString(DCM_StudyTime, studyTime);
  202. dataset->findAndGetOFString(DCM_AccessionNumber, accessionNumber);
  203. dataset->findAndGetOFString(DCM_ModalitiesInStudy, modalitiesInStudy);
  204. dataset->findAndGetOFString(DCM_InstitutionName, institutionName);
  205. dataset->findAndGetOFString(DCM_PerformingPhysicianName, performingPhysiciansName);
  206. dataset->findAndGetOFString(DCM_ReferringPhysicianName, referringPhysician);
  207. dataset->findAndGetOFString(DCM_StudyDescription, studyDescription);
  208. dataset->findAndGetOFString(DCM_SeriesDate, seriesDate);
  209. dataset->findAndGetOFString(DCM_SeriesTime, seriesTime);
  210. dataset->findAndGetOFString(DCM_SeriesDescription, seriesDescription);
  211. dataset->findAndGetOFString(DCM_BodyPartExamined, bodyPartExamined);
  212. dataset->findAndGetOFString(DCM_FrameOfReferenceUID, frameOfReferenceUID);
  213. dataset->findAndGetOFString(DCM_ContrastBolusAgent, contrastAgent);
  214. dataset->findAndGetOFString(DCM_ScanningSequence, scanningSequence);
  215. dataset->findAndGetSint32(DCM_SeriesNumber, seriesNumber);
  216. dataset->findAndGetSint32(DCM_AcquisitionNumber, acquisitionNumber);
  217. dataset->findAndGetSint32(DCM_EchoNumbers, echoNumber);
  218. dataset->findAndGetSint32(DCM_TemporalPositionIdentifier, temporalPosition);
  219. logger.debug( "Adding new items to database:" );
  220. logger.debug( "studyID: " + QString(studyID.c_str()) );
  221. logger.debug( "seriesInstanceUID: " + QString(seriesInstanceUID.c_str()) );
  222. logger.debug( "Patient's Name: " + QString(patientsName.c_str()) );
  223. //-----------------------
  224. //Add Patient to Database
  225. //-----------------------
  226. //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
  227. bool patientExists = false;
  228. if(d->lastPatientID.compare(patientID) || d->lastPatientsBirthDate.compare(patientsBirthDate) || d->lastPatientsName.compare(patientsName))
  229. {
  230. //Check if patient is already present in the db
  231. QSqlQuery check_exists_query(ctkDICOMDatabase.database());
  232. std::stringstream check_exists_query_string;
  233. check_exists_query_string << "SELECT * FROM Patients WHERE PatientID = '" << patientID << "'";
  234. this->loggedExec(check_exists_query, check_exists_query_string.str().c_str());
  235. /// we check only patients with the same PatientID
  236. /// PatientID is not unique in DICOM, so we also compare Name and BirthDate
  237. /// and assume this is sufficient
  238. while (check_exists_query.next())
  239. {
  240. if (
  241. check_exists_query.record().value("PatientsName").toString() == patientsName.c_str() &&
  242. check_exists_query.record().value("PatientsBirthDate").toString() == patientsBirthDate.c_str()
  243. )
  244. {
  245. /// found it
  246. patientUID = check_exists_query.value(check_exists_query.record().indexOf("UID")).toInt();
  247. patientExists = true;
  248. break;
  249. }
  250. }
  251. check_exists_query.finish();
  252. if(!patientExists)
  253. {
  254. QSqlQuery insert_patient_query(ctkDICOMDatabase.database());
  255. std::stringstream query_string;
  256. query_string << "INSERT INTO Patients VALUES( NULL,'"
  257. << patientsName << "','"
  258. << patientID << "','"
  259. << patientsBirthDate << "','"
  260. << patientsBirthTime << "','"
  261. << patientsSex << "','"
  262. << patientsAge << "','"
  263. << patientComments << "')";
  264. this->loggedExec(insert_patient_query, query_string.str().c_str());
  265. patientUID = insert_patient_query.lastInsertId().toInt();
  266. insert_patient_query.finish();
  267. QString patientUIDQString;
  268. patientUIDQString.setNum(patientUID);
  269. logger.debug( "New patient inserted: " + patientUIDQString );
  270. }
  271. }
  272. else
  273. {
  274. patientUID = d->lastPatientUID;
  275. }
  276. /// keep this for the next image
  277. d->lastPatientUID = patientUID;
  278. d->lastPatientID = patientID;
  279. d->lastPatientsBirthDate = patientsBirthDate;
  280. d->lastPatientsName = patientsName;
  281. //---------------------
  282. //Add Study to Database
  283. //---------------------
  284. if(d->lastStudyInstanceUID.compare(studyInstanceUID))
  285. {
  286. QSqlQuery check_exists_query(ctkDICOMDatabase.database());
  287. std::stringstream check_exists_query_string;
  288. check_exists_query_string << "SELECT * FROM Studies WHERE StudyInstanceUID = '" << studyInstanceUID << "'";
  289. this->loggedExec(check_exists_query, check_exists_query_string.str().c_str());
  290. logger.debug( "Checking for study: " + QString(studyInstanceUID.c_str()) );
  291. if(!check_exists_query.next())
  292. {
  293. QSqlQuery insert_query(ctkDICOMDatabase.database());
  294. std::stringstream query_string;
  295. // TODO: all INSERTS should be changed to use the prepare/bindValue methods
  296. // to avoid quoting issues
  297. insert_query.prepare("INSERT INTO Studies (StudyInstanceUID, PatientsUID, StudyID, StudyDate, StudyTime, AccessionNumber, ModalitiesInStudy, InstitutionName, ReferringPhysician, PerformingPhysiciansName, StudyDescription) VALUES (:StudyInstanceUID, :PatientsUID, :StudyID, :StudyDate, :StudyTime, :AccessionNumber, :ModalitiesInStudy, :InstitutionName, :ReferringPhysician, :PerformingPhysiciansName, :StudyDescription)");
  298. insert_query.bindValue(":StudyInstanceUID", QString(studyInstanceUID.c_str()));
  299. insert_query.bindValue(":PatientsUID", patientUID);
  300. insert_query.bindValue(":StudyID", QString(studyID.c_str()));
  301. insert_query.bindValue(":StudyDate", QDate::fromString(studyDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd"));
  302. insert_query.bindValue(":StudyTime", QString(studyTime.c_str()));
  303. insert_query.bindValue(":AccessionNumber", QString(accessionNumber.c_str()));
  304. insert_query.bindValue(":ModalitiesInStudy", QString(modalitiesInStudy.c_str()));
  305. insert_query.bindValue(":InstitutionName", QString(institutionName.c_str()));
  306. insert_query.bindValue(":ReferringPhysician", QString(referringPhysician.c_str()));
  307. insert_query.bindValue(":PerformingPhysiciansName", QString(performingPhysiciansName.c_str()));
  308. insert_query.bindValue(":StudyDescription", QString(studyDescription.c_str()));
  309. this->loggedExec(insert_query);
  310. logger.debug( "Inserted study: " + QString(studyInstanceUID.c_str()) );
  311. }
  312. }
  313. d->lastStudyInstanceUID = studyInstanceUID;
  314. //----------------------
  315. //Add Series to Database
  316. //----------------------
  317. if(d->lastSeriesInstanceUID.compare(seriesInstanceUID))
  318. {
  319. QSqlQuery check_exists_query(ctkDICOMDatabase.database());
  320. std::stringstream check_exists_query_string;
  321. check_exists_query_string << "SELECT * FROM Series WHERE SeriesInstanceUID = '" << seriesInstanceUID << "'";
  322. this->loggedExec(check_exists_query, check_exists_query_string.str().c_str());
  323. logger.debug( "Checking series: " + QString(seriesInstanceUID.c_str()) );
  324. if(!check_exists_query.next())
  325. {
  326. QSqlQuery insert_query(ctkDICOMDatabase.database());
  327. std::stringstream query_string;
  328. query_string << "INSERT INTO Series VALUES('"
  329. << seriesInstanceUID << "','"
  330. << studyInstanceUID << "','"
  331. << static_cast<int>(seriesNumber) << "','"
  332. << QDate::fromString(seriesDate.c_str(), "yyyyMMdd").toString("yyyy-MM-dd").toStdString() << "','"
  333. << seriesTime << "','"
  334. << seriesDescription << "','"
  335. << bodyPartExamined << "','"
  336. << frameOfReferenceUID << "','"
  337. << static_cast<int>(acquisitionNumber) << "','"
  338. << contrastAgent << "','"
  339. << scanningSequence << "','"
  340. << static_cast<int>(echoNumber) << "','"
  341. << static_cast<int>(temporalPosition) << "')";
  342. this->loggedExec(insert_query, query_string.str().c_str());
  343. logger.debug( "Inserted series: " + QString(seriesInstanceUID.c_str()) );
  344. }
  345. }
  346. d->lastSeriesInstanceUID = seriesInstanceUID;
  347. QString studySeriesDirectory = QString(studyInstanceUID.c_str()) + "/" + seriesInstanceUID.c_str();
  348. //----------------------------------
  349. //Move file to destination directory
  350. //----------------------------------
  351. QString finalFilePath(filePath);
  352. if (!destinationDirectoryName.isEmpty())
  353. {
  354. QFile currentFile( filePath );
  355. QDir destinationDir(destinationDirectoryName + "/dicom");
  356. finalFilePath = sopInstanceUID.c_str();
  357. if (createHierarchy)
  358. {
  359. destinationDir.mkpath(studySeriesDirectory);
  360. finalFilePath.prepend( destinationDir.absolutePath() + "/" + studySeriesDirectory + "/" );
  361. }
  362. currentFile.copy(finalFilePath);
  363. logger.debug( "Copy file from: " + filePath );
  364. logger.debug( "Copy file to : " + finalFilePath );
  365. }
  366. logger.debug(QString("finalFilePath: ") + finalFilePath);
  367. if (createThumbnails)
  368. {
  369. if(d->thumbnailGenerator)
  370. {
  371. QString thumbnailBaseDir = ctkDICOMDatabase.databaseDirectory() + "/thumbs/";
  372. QString thumbnailFilename = thumbnailBaseDir + "/" + ctkDICOMDatabase.pathForDataset(dataset) + ".png";
  373. QFileInfo thumbnailInfo(thumbnailFilename);
  374. if ( ! ( thumbnailInfo.exists() && thumbnailInfo.lastModified() < QFileInfo(finalFilePath).lastModified() ) )
  375. {
  376. QDir(thumbnailBaseDir).mkpath(studySeriesDirectory);
  377. DicomImage dcmtkImage(QDir::toNativeSeparators(finalFilePath).toStdString().c_str());
  378. d->thumbnailGenerator->generateThumbnail(&dcmtkImage, thumbnailFilename);
  379. }
  380. }
  381. }
  382. //------------------------
  383. //Add Filename to Database
  384. //------------------------
  385. // std::stringstream relativeFilePath;
  386. // relativeFilePath << seriesInstanceUID.c_str() << "/" << currentFilePath.getFileName();
  387. logger.debug(QString("Adding file path to dabase: ") + finalFilePath);
  388. QSqlQuery check_exists_query(ctkDICOMDatabase.database());
  389. std::stringstream check_exists_query_string;
  390. // check_exists_query_string << "SELECT * FROM Images WHERE Filename = '" << relativeFilePath.str() << "'";
  391. check_exists_query_string << "SELECT * FROM Images WHERE SOPInstanceUID = '" << sopInstanceUID << "'";
  392. this->loggedExec(check_exists_query, check_exists_query_string.str().c_str());
  393. if(!check_exists_query.next())
  394. {
  395. QSqlQuery insert_query(ctkDICOMDatabase.database());
  396. std::stringstream query_string;
  397. //To save absolute path: destDirectoryPath.str()
  398. query_string << "INSERT INTO Images VALUES('"
  399. << sopInstanceUID << "','" << finalFilePath.toStdString() << "','" << seriesInstanceUID << "','" << QDateTime::currentDateTime().toString(Qt::ISODate).toStdString() << "')";
  400. this->loggedExec(insert_query, query_string.str().c_str());
  401. logger.debug(QString("added file path to dabase: ") + query_string.str().c_str());
  402. }
  403. }
  404. //------------------------------------------------------------------------------
  405. void ctkDICOMIndexer::addDirectory(ctkDICOMDatabase& ctkDICOMDatabase,
  406. const QString& directoryName,
  407. const QString& destinationDirectoryName,
  408. bool createHierarchy,
  409. bool createThumbnails)
  410. {
  411. const std::string src_directory(directoryName.toStdString());
  412. OFList<OFString> originalDcmtkFileNames;
  413. OFList<OFString> dcmtkFileNames;
  414. OFStandard::searchDirectoryRecursively( QDir::toNativeSeparators(src_directory.c_str()).toAscii().data(), originalDcmtkFileNames, "", "");
  415. // hack to reverse list of filenames (not neccessary when image loading works correctly)
  416. for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
  417. {
  418. dcmtkFileNames.push_front( *iter );
  419. }
  420. OFListIterator(OFString) iter = dcmtkFileNames.begin();
  421. OFListIterator(OFString) last = dcmtkFileNames.end();
  422. if(iter == last) return;
  423. emit foundFilesToIndex(dcmtkFileNames.size());
  424. /* iterate over all input filenames */
  425. int fileNumber = 0;
  426. while (iter != last)
  427. {
  428. emit indexingFileNumber(++fileNumber);
  429. QString filePath((*iter).c_str());
  430. this->addFile(ctkDICOMDatabase, filePath, destinationDirectoryName, createHierarchy, createThumbnails);
  431. ++iter;
  432. }
  433. }
  434. //------------------------------------------------------------------------------
  435. void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& ctkDICOMDatabase, const QString& directoryName)
  436. {
  437. /// get all filenames from the database
  438. QSqlQuery allFilesQuery(ctkDICOMDatabase.database());
  439. QStringList databaseFileNames;
  440. QStringList filesToRemove;
  441. this->loggedExec(allFilesQuery, "SELECT Filename from Images;");
  442. while (allFilesQuery.next())
  443. {
  444. QString fileName = allFilesQuery.value(0).toString();
  445. databaseFileNames.append(fileName);
  446. if (! QFile::exists(fileName) )
  447. {
  448. filesToRemove.append(fileName);
  449. }
  450. }
  451. QSet<QString> filesytemFiles;
  452. QDirIterator dirIt(directoryName);
  453. while (dirIt.hasNext())
  454. {
  455. filesytemFiles.insert(dirIt.next());
  456. }
  457. // TODO: it looks like this function was never finished...
  458. //
  459. // I guess the next step is to remove all filesToRemove from the database
  460. // and also to add filesystemFiles into the database tables
  461. }
  462. //------------------------------------------------------------------------------
  463. void ctkDICOMIndexer::setThumbnailGenerator(ctkDICOMAbstractThumbnailGenerator *generator){
  464. Q_D(ctkDICOMIndexer);
  465. d->thumbnailGenerator = generator;
  466. }
  467. //------------------------------------------------------------------------------
  468. ctkDICOMAbstractThumbnailGenerator* ctkDICOMIndexer::thumbnailGenerator(){
  469. Q_D(ctkDICOMIndexer);
  470. return d->thumbnailGenerator;
  471. }