Skip to content

Commit

Permalink
ENH: Make DICOM database relocatable
Browse files Browse the repository at this point in the history
Previously full path was stored to DICOM files that were copied into the DICOM database. This made it impossible to move the database into any other location or store in on removable storage (such as a USB stick, which may be mapped with different path on different computers).

Now files that are copied (not linked) to the DICOM database are stored with path relative to the DICOM database folder (where the .sql files are located).

Also, DICOM database location can now be specified with relative path in application settings. This allows the database to be moved along with the application. For example, to implement a DICOM viewer that opens DICOM database in a folder relative to the application's location (e.g., use the application as a viewer on a DICOM CD).
  • Loading branch information
lassoan committed Dec 31, 2020
1 parent 18715f1 commit 3392fd0
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 93 deletions.
23 changes: 23 additions & 0 deletions Libs/Core/ctkCorePythonQtDecorators.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

// CTK includes
#include <ctkBooleanMapper.h>
#include <ctkUtils.h>
#include <ctkErrorLogContext.h>
#include <ctkWorkflowStep.h>
#include <ctkWorkflowTransitions.h>
Expand Down Expand Up @@ -234,10 +235,32 @@ public Q_SLOTS:

};

//-----------------------------------------------------------------------------
class PythonQtWrapper_CTKCore : public QObject
{
Q_OBJECT

public Q_SLOTS:
QString static_ctkCoreUtils_absolutePathFromInternal(const QString& internalPath, const QString& basePath)
{
return ctk::absolutePathFromInternal(internalPath, basePath);
}

QString static_ctkCoreUtils_internalPathFromAbsolute(const QString& absolutePath, const QString& basePath)
{
return ctk::internalPathFromAbsolute(absolutePath, basePath);
}
};

//-----------------------------------------------------------------------------
void initCTKCorePythonQtDecorators()
{
PythonQt::self()->addDecorators(new ctkCorePythonQtDecorators);

// PythonQt doesn't support wrapping a static function and adding it to the top-level
// ctk module. This exposes static functions from ctkCoreUtils as ctk.ctkCoreUtils.absolutePathFromInternal(), etc.
// Note that PythonQtWrapper_CTKCore installs itself as ctk.ctk but using that same module here would replace PythonQtWrapper_CTKCore.
PythonQt::self()->registerCPPClass("ctkCoreUtils", "", "CTKCore", PythonQtCreateObject<PythonQtWrapper_CTKCore>);
}

#endif
41 changes: 41 additions & 0 deletions Libs/Core/ctkUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,44 @@ qint64 ctk::msecsTo(const QDateTime& t1, const QDateTime& t2)
return static_cast<qint64>(utcT1.daysTo(utcT2)) * static_cast<qint64>(1000*3600*24)
+ static_cast<qint64>(utcT1.time().msecsTo(utcT2.time()));
}

//------------------------------------------------------------------------------
QString ctk::absolutePathFromInternal(const QString& internalPath, const QString& basePath)
{
QDir databaseDirectory(basePath);
if (QFileInfo(internalPath).isRelative())
{
return QDir::cleanPath(databaseDirectory.filePath(internalPath));
}
else
{
return internalPath;
}
}

//------------------------------------------------------------------------------
QString ctk::internalPathFromAbsolute(const QString& absolutePath, const QString& basePath)
{
// Make it a relative path if it is withing the database folder
if (!QFileInfo(absolutePath).isAbsolute())
{
return absolutePath;
}
QString databaseFolderClean = QDir::cleanPath(QDir::fromNativeSeparators(basePath));
QString fileNameClean = QDir::cleanPath(QDir::fromNativeSeparators(absolutePath));
#ifdef Q_OS_WIN32
Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
#else
Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
#endif
if (fileNameClean.startsWith(databaseFolderClean, sensitivity))
{
// file is in the database folder, make it a relative path
// (remove size+1 to remove the leading forward slash)
return fileNameClean.remove(0, databaseFolderClean.size() + 1);
}
else
{
return absolutePath;
}
}
11 changes: 11 additions & 0 deletions Libs/Core/ctkUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,17 @@ QString CTK_CORE_EXPORT qtHandleToString(Qt::HANDLE handle);
/// bumping the minimum required Qt version for CTK.
qint64 CTK_CORE_EXPORT msecsTo(const QDateTime& t1, const QDateTime& t2);

/// Get absolute path from an "internal" path. If internal path is already an absolute path
/// then that is returned unchanged. If internal path is relative path then basePath is used
/// as a basis (prepended to internalPath).
QString CTK_CORE_EXPORT absolutePathFromInternal(const QString& internalPath, const QString& basePath);

/// Get "internal" path from an absolute path. internalPath will be a relative path if
/// absolutePath is within the basePath, otherwise interalPath will be the same as absolutePath.
/// This is useful for paths/directories relative to a base folder, to make the data or application relocatable.
/// Absolute path can be retrieved from an internal path using absolutePathFromInternal function.
QString CTK_CORE_EXPORT internalPathFromAbsolute(const QString& absolutePath, const QString& basePath);

}

#endif
Loading

0 comments on commit 3392fd0

Please sign in to comment.