Browse Source

Moved (and fixed) code for checking whether database in memory into helper function. Added documentation. Added exception in case the database cannot be initialized.

Michael Onken 13 years ago
parent
commit
c5ecbd73ed
2 changed files with 161 additions and 118 deletions
  1. 12 7
      Libs/DICOM/Core/ctkDICOMDatabase.cpp
  2. 149 111
      Libs/DICOM/Core/ctkDICOMDatabase.h

+ 12 - 7
Libs/DICOM/Core/ctkDICOMDatabase.cpp

@@ -77,6 +77,7 @@ public:
   void registerCompressionLibraries();
   bool executeScript(const QString script);
 
+  /// Name of the database file (i.e. for SQLITE the sqlite file)
   QString      DatabaseFileName;
   QString      LastError;
   QSqlDatabase Database;
@@ -127,7 +128,7 @@ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& c
 {
   Q_D(ctkDICOMDatabase);
   d->DatabaseFileName = databaseFile;
-  d->Database = QSqlDatabase::addDatabase("QSQLITE",connectionName);
+  d->Database = QSqlDatabase::addDatabase("QSQLITE", connectionName);
   d->Database.setDatabaseName(databaseFile);
   if ( ! (d->Database.open()) )
     {
@@ -136,9 +137,12 @@ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& c
     }
   if ( d->Database.tables().empty() )
     {
-      initializeDatabase();
+      if (!initializeDatabase())
+        {
+        throw std::runtime_error("Unable to initialize DICOM database!");
+        }
     }
-  if (databaseFile != ":memory")
+  if (!isInMemory())
   {
     QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList(databaseFile),this);
     connect(watcher, SIGNAL( fileChanged(const QString&)),this, SIGNAL ( databaseChanged() ) );
@@ -190,9 +194,9 @@ const QString ctkDICOMDatabase::databaseFilename() const {
 const QString ctkDICOMDatabase::databaseDirectory() const {
   QString databaseFile = databaseFilename();
   if (!QFileInfo(databaseFile).isAbsolute())
-  {
+    {
     databaseFile.prepend(QDir::currentPath() + "/");
-  }
+    }
   return QFileInfo ( databaseFile ).absoluteDir().path();
 }
 
@@ -494,7 +498,8 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, bool storeFile, bool genera
       statement.bindValue ( 2, QString ( patientsBirthDate.c_str() ) );
       statement.bindValue ( 3, QString ( patientsBirthTime.c_str() ) );
       statement.bindValue ( 4, QString ( patientsSex.c_str() ) );
-      statement.bindValue ( 5, QString ( patientsAge.c_str() ) );
+      // TODO: shift patient's age to study, since this is not a patient level attribute in images
+      // statement.bindValue ( 5, QString ( patientsAge.c_str() ) );
       statement.bindValue ( 6, QString ( patientComments.c_str() ) );
       statement.exec ();
       patientUID = statement.lastInsertId().toInt();
@@ -593,7 +598,7 @@ void ctkDICOMDatabase::insert ( DcmDataset *dataset, bool storeFile, bool genera
       }
   }
 
-  if (d->DatabaseFileName == ":memory:")
+  if (isInMemory())
     {
       emit databaseChanged();
     }

+ 149 - 111
Libs/DICOM/Core/ctkDICOMDatabase.h

@@ -1,111 +1,149 @@
-/*=========================================================================
-
-  Library:   CTK
-
-  Copyright (c) 2010
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0.txt
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-
-=========================================================================*/
-
-#ifndef __ctkDICOMDatabase_h
-#define __ctkDICOMDatabase_h
-
-// Qt includes 
-#include <QObject>
-#include <QStringList>
-#include <QSqlDatabase>
-
-#include "ctkDICOMCoreExport.h"
-
-class ctkDICOMDatabasePrivate;
-class DcmDataset;
-class ctkDICOMAbstractThumbnailGenerator;
-
-class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
-{
-  Q_OBJECT
-public:
-  explicit ctkDICOMDatabase(QObject *parent = 0);
-  explicit ctkDICOMDatabase(QString databaseFile);
-  virtual ~ctkDICOMDatabase();
-
-  const QSqlDatabase& database() const;
-  const QString lastError() const;
-  const QString databaseFilename() const;
-  const QString databaseDirectory() const;
-  bool isInMemory() const;
-
-  ///
-  /// set thumbnail generator object
-  void setThumbnailGenerator(ctkDICOMAbstractThumbnailGenerator* generator);
-  ///
-  /// get thumbnail genrator object
-  ctkDICOMAbstractThumbnailGenerator* thumbnailGenerator();
-
-  ///
-  /// open the SQLite database in @param databaseFile . If the file does not
-  /// exist, a new database is created and initialized with the
-  /// default schema
-  ///
-  /// @param databaseFile TODO
-  /// @param connectionName TODO
-  Q_INVOKABLE virtual void openDatabase(const QString databaseFile, const QString& connectionName = "DICOM-DB" );
-
-  ///
-  /// close the database. It must not be used afterwards.
-  Q_INVOKABLE void closeDatabase();
-  ///
-  /// delete all data and reinitialize the database.
-  Q_INVOKABLE bool initializeDatabase(const char* schemaFile = ":/dicom/dicom-schema.sql");
-
-  ///
-  /// \brief database accessors
-  Q_INVOKABLE QStringList studiesForPatient (QString patientUID);
-  Q_INVOKABLE QStringList seriesForStudy (QString studyUID);
-  Q_INVOKABLE QStringList filesForSeries (QString seriesUID);
-
-  ///
-  /// \brief load the header from a file and allow access to elements
-  Q_INVOKABLE void loadInstanceHeader (QString sopInstanceUID);
-  Q_INVOKABLE void loadFileHeader (QString fileName);
-  Q_INVOKABLE QStringList headerKeys ();
-  Q_INVOKABLE QString headerValue (QString key);
-
-  /**
-   * Will create an entry in the appropriate tables for this dataset.
-   */
-  // void insert ( DcmDataset* dataset, QString filename );
-  /**
-   * Insert into the database if not already exsting.
-   */
-  void insert ( DcmDataset *dataset, bool storeFile = true, bool generateThumbnail = true);
-  /***
-    * Helper method: get the path that should be used to store this  image.
-    */
-  QString pathForDataset( DcmDataset *dataset);
-
-signals:
-  void databaseChanged();
-
-protected:
-  QScopedPointer<ctkDICOMDatabasePrivate> d_ptr;
-
-
-
-private:
-  Q_DECLARE_PRIVATE(ctkDICOMDatabase);
-  Q_DISABLE_COPY(ctkDICOMDatabase);
-};
-
-#endif
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) 2010
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkDICOMDatabase_h
+#define __ctkDICOMDatabase_h
+
+// Qt includes
+#include <QObject>
+#include <QStringList>
+#include <QSqlDatabase>
+
+#include "ctkDICOMCoreExport.h"
+
+class ctkDICOMDatabasePrivate;
+class DcmDataset;
+class ctkDICOMAbstractThumbnailGenerator;
+
+
+/// Class handling a database of DICOM objects. So far, an underlying
+/// SQLITE database is used for that. Usually, added DICOM objects are also
+/// stored within the file system.
+/// The SQLITE database file can be specified by the user. SQLITE (and this
+/// class) also support a special in memory mode, where no database file is created
+/// but the database is completely kept in memory (and after exiting the program,
+/// vanishes). If in "memory mode", the objects are not written to disk,
+/// otherwise they are stored in a subdirectory of the SQLITE database file
+/// directory called "dicom". Inside, a folder structure created which contains
+/// a directoy for each study, containing a directory for each series, containing
+/// a file for each object. The corresponding UIDs are used as filenames.
+/// Thumbnais for each image can be created; if so, they are stored in a directory
+/// parallel to "dicom" directory called "thumbs".
+class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
+{
+  Q_OBJECT
+public:
+  explicit ctkDICOMDatabase(QObject *parent = 0);
+  explicit ctkDICOMDatabase(QString databaseFile);
+  virtual ~ctkDICOMDatabase();
+
+  const QSqlDatabase& database() const;
+  const QString lastError() const;
+  const QString databaseFilename() const;
+
+  ///
+  /// Returns the absolute path of the database directory
+  /// (where the database file resides in) in OS-prefered path format.
+  /// @return Absolute path to database directory
+  const QString databaseDirectory() const;
+
+  ///
+  /// Returns whether the database only resides in memory, i.e. the
+  /// SQLITE DB is not written to stored to disk and DICOM objects are not
+  /// stored to the file system.
+  /// @return True if in memory mode, false otherwise.
+  bool isInMemory() const;
+
+  ///
+  /// set thumbnail generator object
+  void setThumbnailGenerator(ctkDICOMAbstractThumbnailGenerator* generator);
+  ///
+  /// get thumbnail genrator object
+  ctkDICOMAbstractThumbnailGenerator* thumbnailGenerator();
+
+  ///
+  /// open the SQLite database in @param databaseFile . If the file does not
+  /// exist, a new database is created and initialized with the
+  /// default schema
+  ///
+  /// @param databaseFile The file to store the SQLITE database should be
+  ///        stored to. If specified with ":memory:", the database is not
+  ///        written to disk at all but instead only kept in memory (and
+  ///        thus expires after destruction of this object).
+  /// @param connectionName The database connection name.
+  Q_INVOKABLE virtual void openDatabase(const QString databaseFile,
+                                        const QString& connectionName = "DICOM-DB" );
+
+  ///
+  /// close the database. It must not be used afterwards.
+  Q_INVOKABLE void closeDatabase();
+  ///
+  /// delete all data and reinitialize the database.
+  Q_INVOKABLE bool initializeDatabase(const char* schemaFile = ":/dicom/dicom-schema.sql");
+
+  ///
+  /// \brief database accessors
+  Q_INVOKABLE QStringList studiesForPatient (QString patientUID);
+  Q_INVOKABLE QStringList seriesForStudy (QString studyUID);
+  Q_INVOKABLE QStringList filesForSeries (QString seriesUID);
+
+  ///
+  /// \brief load the header from a file and allow access to elements
+  Q_INVOKABLE void loadInstanceHeader (QString sopInstanceUID);
+  Q_INVOKABLE void loadFileHeader (QString fileName);
+  Q_INVOKABLE QStringList headerKeys ();
+  Q_INVOKABLE QString headerValue (QString key);
+
+  /** Insert into the database if not already exsting.
+    *  @param dataset The dataset to store into the database. Usually, this is
+    *                 is a complete DICOM object, like a complete image. However
+    *                 the database also inserts partial objects, like studyl
+    *                 information to the database, even if no image data is
+    *                 contained. This can be helpful to store results from
+    *                 querying the PACS for patient/study/series or image
+    *                 information, where a full hierarchy is only constructed
+    *                 after some queries.
+    *  @param storeFile If store file is set (default), then the dataset will
+    *                   be stored to disk. Note that in case of a memory-only
+    *                   database, this flag is ignored. Usually, this flag
+    *                   does only make sense if a full object is received.
+    *  @param @generateThumbnail If true, a thumbnail is generated.
+    */
+  void insert ( DcmDataset *dataset, bool storeFile = true, bool generateThumbnail = true);
+  /***
+    * Helper method: get the path that should be used to store this image.
+    */
+  QString pathForDataset( DcmDataset *dataset);
+
+signals:
+  void databaseChanged();
+
+protected:
+  QScopedPointer<ctkDICOMDatabasePrivate> d_ptr;
+
+
+
+private:
+  Q_DECLARE_PRIVATE(ctkDICOMDatabase);
+  Q_DISABLE_COPY(ctkDICOMDatabase);
+};
+
+#endif
+