ctkDICOMIndexer.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. #include <tr1/functional>
  15. // Qt includes
  16. #include <QSqlQuery>
  17. #include <QSqlRecord>
  18. #include <QSqlError>
  19. #include <QVariant>
  20. #include <QDate>
  21. #include <QStringList>
  22. #include <QSet>
  23. #include <QFile>
  24. #include <QDirIterator>
  25. #include <QFileInfo>
  26. #include <QDebug>
  27. #include <QPixmap>
  28. #include <QtConcurrentRun>
  29. // ctkDICOM includes
  30. #include "ctkLogger.h"
  31. #include "ctkDICOMIndexer.h"
  32. #include "ctkDICOMIndexerPrivate.h"
  33. #include "ctkDICOMDatabase.h"
  34. // DCMTK includes
  35. #include <dcmtk/dcmdata/dcfilefo.h>
  36. #include <dcmtk/dcmdata/dcfilefo.h>
  37. #include <dcmtk/dcmdata/dcdeftag.h>
  38. #include <dcmtk/dcmdata/dcdatset.h>
  39. #include <dcmtk/ofstd/ofcond.h>
  40. #include <dcmtk/ofstd/ofstring.h>
  41. #include <dcmtk/ofstd/ofstd.h> /* for class OFStandard */
  42. #include <dcmtk/dcmdata/dcddirif.h> /* for class DicomDirInterface */
  43. #include <dcmtk/dcmimgle/dcmimage.h> /* for class DicomImage */
  44. #include <dcmtk/dcmimage/diregist.h> /* include support for color images */
  45. class AddFileFunctor
  46. {
  47. public:
  48. AddFileFunctor(ctkDICOMIndexer* indexer, ctkDICOMDatabase& database,
  49. const QString& destinationDirectoryName = "")
  50. : Indexer(indexer), Database(database), DestinationDirectoryName(destinationDirectoryName) { }
  51. bool operator()(const QString &filePath)
  52. {
  53. Indexer->addFile(Database,filePath,DestinationDirectoryName);
  54. return false; // make sure it is removed;
  55. }
  56. ctkDICOMIndexer* Indexer;
  57. ctkDICOMDatabase& Database;
  58. QString DestinationDirectoryName;
  59. };
  60. //------------------------------------------------------------------------------
  61. static ctkLogger logger("org.commontk.dicom.DICOMIndexer" );
  62. //------------------------------------------------------------------------------
  63. //------------------------------------------------------------------------------
  64. // ctkDICOMIndexerPrivate methods
  65. //------------------------------------------------------------------------------
  66. ctkDICOMIndexerPrivate::ctkDICOMIndexerPrivate(ctkDICOMIndexer& o) : q_ptr(&o), Canceled(false), CurrentPercentageProgress(-1)
  67. {
  68. Q_Q(ctkDICOMIndexer);
  69. connect(&DirectoryImportWatcher,SIGNAL(progressValueChanged(int)),this,SLOT(OnProgress(int)));
  70. connect(&DirectoryImportWatcher,SIGNAL(finished()),q,SIGNAL(indexingComplete()));
  71. connect(&DirectoryImportWatcher,SIGNAL(canceled()),q,SIGNAL(indexingComplete()));
  72. }
  73. //------------------------------------------------------------------------------
  74. ctkDICOMIndexerPrivate::~ctkDICOMIndexerPrivate()
  75. {
  76. }
  77. void ctkDICOMIndexerPrivate::OnProgress(int progress)
  78. {
  79. Q_Q(ctkDICOMIndexer);
  80. int newPercentageProgress = ( 100 * DirectoryImportFuture.progressValue() ) / DirectoryImportFuture.progressMaximum();
  81. if (newPercentageProgress != CurrentPercentageProgress)
  82. {
  83. CurrentPercentageProgress = newPercentageProgress;
  84. emit q->progress(newPercentageProgress);
  85. }
  86. }
  87. //------------------------------------------------------------------------------
  88. //------------------------------------------------------------------------------
  89. // ctkDICOMIndexer methods
  90. //------------------------------------------------------------------------------
  91. ctkDICOMIndexer::ctkDICOMIndexer(QObject *parent):d_ptr(new ctkDICOMIndexerPrivate(*this))
  92. {
  93. Q_UNUSED(parent);
  94. }
  95. //------------------------------------------------------------------------------
  96. ctkDICOMIndexer::~ctkDICOMIndexer()
  97. {
  98. }
  99. //------------------------------------------------------------------------------
  100. void ctkDICOMIndexer::addFile(ctkDICOMDatabase& database,
  101. const QString filePath,
  102. const QString& destinationDirectoryName)
  103. {
  104. std::cout << filePath.toStdString();
  105. if (!destinationDirectoryName.isEmpty())
  106. {
  107. logger.warn("Ignoring destinationDirectoryName parameter, just taking it as indication we should copy!");
  108. }
  109. emit indexingFilePath(filePath);
  110. database.insert(filePath, !destinationDirectoryName.isEmpty(), true);
  111. }
  112. //------------------------------------------------------------------------------
  113. void ctkDICOMIndexer::addDirectory(ctkDICOMDatabase& ctkDICOMDatabase,
  114. const QString& directoryName,
  115. const QString& destinationDirectoryName)
  116. {
  117. Q_D(ctkDICOMIndexer);
  118. const std::string src_directory(directoryName.toStdString());
  119. OFList<OFString> originalDcmtkFileNames;
  120. OFList<OFString> dcmtkFileNames;
  121. OFStandard::searchDirectoryRecursively( QDir::toNativeSeparators(src_directory.c_str()).toAscii().data(), originalDcmtkFileNames, "", "");
  122. int totalNumberOfFiles = originalDcmtkFileNames.size();
  123. // hack to reverse list of filenames (not neccessary when image loading works correctly)
  124. for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
  125. {
  126. dcmtkFileNames.push_front( *iter );
  127. }
  128. OFListIterator(OFString) iter = dcmtkFileNames.begin();
  129. OFListIterator(OFString) last = dcmtkFileNames.end();
  130. if(iter == last) return;
  131. emit foundFilesToIndex(totalNumberOfFiles);
  132. /* iterate over all input filenames */
  133. int fileNumber = 0;
  134. int currentProgress = -1;
  135. d->Canceled = false;
  136. while (iter != last)
  137. {
  138. if (d->Canceled)
  139. {
  140. break;
  141. }
  142. emit indexingFileNumber(++fileNumber);
  143. int newProgress = ( fileNumber * 100 ) / totalNumberOfFiles;
  144. if (newProgress != currentProgress)
  145. {
  146. currentProgress = newProgress;
  147. emit progress( currentProgress );
  148. }
  149. QString filePath((*iter).c_str());
  150. d->FilesToIndex << filePath;
  151. ++iter;
  152. }
  153. d->DirectoryImportFuture = QtConcurrent::filter(d->FilesToIndex,AddFileFunctor(this,ctkDICOMDatabase,destinationDirectoryName));
  154. d->DirectoryImportWatcher.setFuture(d->DirectoryImportFuture);
  155. }
  156. //------------------------------------------------------------------------------
  157. void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& dicomDatabase, const QString& directoryName)
  158. {
  159. Q_UNUSED(dicomDatabase);
  160. Q_UNUSED(directoryName);
  161. /*
  162. * Probably this should go to the database class as well
  163. * Or we have to extend the interface to make possible what we do here
  164. * without using SQL directly
  165. /// get all filenames from the database
  166. QSqlQuery allFilesQuery(dicomDatabase.database());
  167. QStringList databaseFileNames;
  168. QStringList filesToRemove;
  169. this->loggedExec(allFilesQuery, "SELECT Filename from Images;");
  170. while (allFilesQuery.next())
  171. {
  172. QString fileName = allFilesQuery.value(0).toString();
  173. databaseFileNames.append(fileName);
  174. if (! QFile::exists(fileName) )
  175. {
  176. filesToRemove.append(fileName);
  177. }
  178. }
  179. QSet<QString> filesytemFiles;
  180. QDirIterator dirIt(directoryName);
  181. while (dirIt.hasNext())
  182. {
  183. filesytemFiles.insert(dirIt.next());
  184. }
  185. // TODO: it looks like this function was never finished...
  186. //
  187. // I guess the next step is to remove all filesToRemove from the database
  188. // and also to add filesystemFiles into the database tables
  189. */
  190. }
  191. //----------------------------------------------------------------------------
  192. void ctkDICOMIndexer::cancel()
  193. {
  194. Q_D(ctkDICOMIndexer);
  195. d->DirectoryImportWatcher.cancel();
  196. }