Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: adds hook for loading directory archetypes #1089

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Base/QTCore/qSlicerCoreIOManager.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -781,3 +781,19 @@ void qSlicerCoreIOManager::setDefaultSceneFileType(QString fileType)
Q_D(qSlicerCoreIOManager);
d->DefaultSceneFileType = fileType;
}

//-----------------------------------------------------------------------------
bool qSlicerCoreIOManager::examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeFileInfo, QString &readerDescription, qSlicerIO::IOProperties &ioProperties)const
{
Q_D(const qSlicerCoreIOManager);
QList<qSlicerFileReader*> res;
foreach(qSlicerFileReader* reader, d->Readers)
{
if (reader->examineFileInfoList(fileInfoList, archetypeFileInfo, ioProperties))
{
readerDescription = reader->description();
return (true);
}
}
return (false);
}
18 changes: 17 additions & 1 deletion Base/QTCore/qSlicerCoreIOManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
#define __qSlicerCoreIOManager_h

// Qt includes
#include <QList>
#include <QFileInfo>
#include <QImage>
#include <QList>
#include <QMap>
#include <QObject>
#include <QVariantMap>
Expand Down Expand Up @@ -170,6 +171,21 @@ class Q_SLICER_BASE_QTCORE_EXPORT qSlicerCoreIOManager:public QObject
/// Defines the file format that should be offered by default when the scene is saved.
Q_INVOKABLE QString defaultSceneFileType()const;

/// Iterates through readers looking at the fileInfoList to see if there is an entry that can serve as
/// an archetype for loading multiple fileInfos. If so, the reader removes the recognized
/// fileInfos from the list and sets the ioProperties so that the corresponding
/// loader will read these files. The archetypeEntry will contain the fileInfo
/// for the archetype and the method returns true. If no pattern is recognized
/// the method returns false.
/// The specific motivating use case is when the file
/// list contains a set of related files, such as a list of image files that
/// are recognized as a volume. But other cases could also make sense, such as when
/// a file format has a set or related files such as textures or material files
/// for a surface model.
/// \sa qSlicerDataDialog
/// \sa qSlicerFileReader
Q_INVOKABLE bool examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeEntry, QString &readerDescription, qSlicerIO::IOProperties &ioProperties)const;

public slots:

/// Defines the file format that should be offered by default when the scene is saved.
Expand Down
6 changes: 6 additions & 0 deletions Base/QTCore/qSlicerFileReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,9 @@ QStringList qSlicerFileReader::loadedNodes()const
Q_D(const qSlicerFileReader);
return d->LoadedNodes;
}

//----------------------------------------------------------------------------
bool qSlicerFileReader::examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeFileInfo, qSlicerIO::IOProperties &ioProperties)const
{
return(false);
}
8 changes: 8 additions & 0 deletions Base/QTCore/qSlicerFileReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#ifndef __qSlicerFileReader_h
#define __qSlicerFileReader_h

// Qt includes
#include <QFileInfo>

// QtCore includes
#include "qSlicerIO.h"
#include "qSlicerBaseQTCoreExport.h"
Expand Down Expand Up @@ -64,6 +67,11 @@ class Q_SLICER_BASE_QTCORE_EXPORT qSlicerFileReader
/// \sa setLoadedNodes(), load()
QStringList loadedNodes()const;

/// Implements the file list examination for the corresponding method in the core
/// IO manager.
/// \sa qSlicerCoreIOManager
virtual bool examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeFileInfo, qSlicerIO::IOProperties &ioProperties)const;

protected:
/// Must be called in load() on success with the list of nodes added into the
/// scene.
Expand Down
38 changes: 37 additions & 1 deletion Base/QTGUI/qSlicerDataDialog.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,43 @@ void qSlicerDataDialogPrivate::addDirectory(const QDir& directory)
bool recursive = true;
QDir::Filters filters =
QDir::AllDirs | QDir::Files | QDir::Readable | QDir::NoDotAndDotDot;
foreach(QFileInfo entry, directory.entryInfoList(filters))
QFileInfoList fileInfoList = directory.entryInfoList(filters);

//
// check to see if any readers recognize the directory contents
// and provide an archetype.
//
qSlicerCoreIOManager* coreIOManager =
qSlicerCoreApplication::application()->coreIOManager();
QString readerDescription;
qSlicerIO::IOProperties ioProperties;
QFileInfo archetypeEntry;
if (coreIOManager->examineFileInfoList(fileInfoList, archetypeEntry, readerDescription, ioProperties))
{
this->addFile(archetypeEntry);
QString filePath = archetypeEntry.absoluteFilePath();
QList<QTableWidgetItem *> items = this->FileWidget->findItems(filePath, Qt::MatchExactly);
if (items.isEmpty())
{
qWarning() << "Couldn't add archetype widget for file: " << filePath;
}
else
{
QTableWidgetItem *item = items[0];
QWidget *cellWidget = this->FileWidget->cellWidget(item->row(), TypeColumn);
QComboBox *descriptionComboBox = dynamic_cast<QComboBox *>(cellWidget);
descriptionComboBox->setCurrentIndex(descriptionComboBox->findText(readerDescription));
cellWidget = this->FileWidget->cellWidget(item->row(), OptionsColumn);
qSlicerIOOptionsWidget *ioOptionsWidget = dynamic_cast<qSlicerIOOptionsWidget *> (cellWidget);
ioOptionsWidget->updateGUI(ioProperties);
}
}

//
// now add any files and directories that weren't filtered
// out by the ioManager
//
foreach(QFileInfo entry, fileInfoList)
{
if (entry.isFile())
{
Expand Down
11 changes: 11 additions & 0 deletions Modules/Loadable/Volumes/qSlicerVolumesIOOptionsWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,14 @@ void qSlicerVolumesIOOptionsWidget::updateColorSelector()
}
}
}

//------------------------------------------------------------------------------
void qSlicerVolumesIOOptionsWidget::updateGUI(const qSlicerIO::IOProperties& ioProperties)
{
Q_D(qSlicerVolumesIOOptionsWidget);
qSlicerIOOptionsWidget::updateGUI(ioProperties);
if (ioProperties.contains("singleFile"))
{
d->SingleFileCheckBox->setChecked(ioProperties["singleFile"].toBool());
}
}
5 changes: 5 additions & 0 deletions Modules/Loadable/Volumes/qSlicerVolumesIOOptionsWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class Q_SLICER_QTMODULES_VOLUMES_EXPORT qSlicerVolumesIOOptionsWidget :
qSlicerVolumesIOOptionsWidget(QWidget *parent=0);
virtual ~qSlicerVolumesIOOptionsWidget();

/// Allows custom handling of image sets as volumes
/// \sa qSlicerVolumesReader
/// \sa qSlicerDataDialog::addDirectory
void updateGUI(const qSlicerIO::IOProperties& ioProperties);

public slots:
virtual void setFileName(const QString& fileName);
virtual void setFileNames(const QStringList& fileNames);
Expand Down
45 changes: 45 additions & 0 deletions Modules/Loadable/Volumes/qSlicerVolumesReader.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@

==============================================================================*/

// std includes
#include <vector>
#include <algorithm>

// Qt includes
#include <QDebug>
#include <QFileInfo>

// SlicerQt includes
Expand All @@ -39,6 +44,9 @@
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>

// ITK includes
#include <itkArchetypeSeriesFileNames.h>

//-----------------------------------------------------------------------------
class qSlicerVolumesReaderPrivate
{
Expand Down Expand Up @@ -205,3 +213,40 @@ bool qSlicerVolumesReader::load(const IOProperties& properties)
}
return node != 0;
}

//-----------------------------------------------------------------------------
bool qSlicerVolumesReader::examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeFileInfo, qSlicerIO::IOProperties &ioProperties)const
{

//
// Check each file to see if it's recognzied as part of a series. If so,
// keep it as the archetype and remove all the others from the list
//
foreach(QFileInfo fileInfo, fileInfoList)
{
itk::ArchetypeSeriesFileNames::Pointer seriesNames = itk::ArchetypeSeriesFileNames::New();
std::vector<std::string> candidateFiles;
seriesNames->SetArchetype(fileInfo.absoluteFilePath().toStdString());
candidateFiles = seriesNames->GetFileNames();
if (candidateFiles.size() > 1)
{
archetypeFileInfo = fileInfo;
QMutableListIterator<QFileInfo> fileInfoIterator(fileInfoList);
while (fileInfoIterator.hasNext())
{
const QString &path = fileInfoIterator.next().absoluteFilePath();
if (path == archetypeFileInfo.absoluteFilePath())
{
continue;
}
if (std::find(candidateFiles.begin(), candidateFiles.end(), path.toStdString()) != candidateFiles.end())
{
fileInfoIterator.remove();
}
}
ioProperties["singleFile"] = false;
return true;
}
}
return false;
}
6 changes: 6 additions & 0 deletions Modules/Loadable/Volumes/qSlicerVolumesReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ class qSlicerVolumesReader
virtual qSlicerIOOptions* options()const;

virtual bool load(const IOProperties& properties);

/// Implements the file list examination for the corresponding method in the core
/// IO manager.
/// \sa qSlicerCoreIOManager
virtual bool examineFileInfoList(QFileInfoList &fileInfoList, QFileInfo &archetypeFileInfo, qSlicerIO::IOProperties &ioProperties)const;

protected:
QScopedPointer<qSlicerVolumesReaderPrivate> d_ptr;

Expand Down