From 354411a61090c197c75ec4aab746160a6e7e355c Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Wed, 11 Jul 2012 11:25:25 -0400 Subject: [PATCH 001/247] Stubs for tagCache mechanism To be filled in with real functionality... --- Libs/DICOM/Core/ctkDICOMDatabase.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 299f47c107..504d44b471 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -166,13 +166,31 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject /// @param key A group,element tag in zero-filled hex /// @param group The group portion of the tag as an integer /// @param element The element portion of the tag as an integer - /// @Returns empty string is element is missing + /// @Returns empty string if element is missing Q_INVOKABLE QString instanceValue (const QString sopInstanceUID, const QString tag); Q_INVOKABLE QString instanceValue (const QString sopInstanceUID, const unsigned short group, const unsigned short element); Q_INVOKABLE QString fileValue (const QString fileName, const QString tag); Q_INVOKABLE QString fileValue (const QString fileName, const unsigned short group, const unsigned short element); bool tagToGroupElement (const QString tag, unsigned short& group, unsigned short& element); + /// + /// \brief store values of previously requested instance elements + /// These are meant to be internal methods used by the instanceValue and fileValue + /// methods, but they can be used by calling classes to populate or access + /// instance tag values as needed. + /// @param sopInstanceUID A string with the uid for a given instance + /// (corresponding file will be found via database) + /// @param key A group,element tag in zero-filled hex + /// @Returns empty string if element for uid is missing from cache + /// + /// Lightweight check of tag cache existence (once db check per runtime) + Q_INVOKABLE bool tagCacheExists (){}; + /// Create a tagCache in the current database. Delete the existing one if it exists. + Q_INVOKABLE bool initializeTagCache (){}; + /// Return the value of a cached tag + Q_INVOKABLE QString cachedTag (const QString sopInstanceUID, const QString tag){}; + Q_INVOKABLE bool cacheTag (const QString sopInstanceUID, const QString tag, const QString value){}; + Q_SIGNALS: void databaseChanged(); From 1670afb9ae88261f47aa4923990053c482eaead6 Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Wed, 11 Jul 2012 11:28:58 -0400 Subject: [PATCH 002/247] Improve style with comment and method separator comment lines --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 12 ++++++++++++ Libs/DICOM/Core/ctkDICOMDatabase.h | 1 + 2 files changed, 13 insertions(+) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 12c4664ce2..dba4cc38c4 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -625,6 +625,7 @@ int ctkDICOMDatabasePrivate::insertPatient(const ctkDICOMDataset& ctkDataset) return dbPatientID; } +//------------------------------------------------------------------------------ void ctkDICOMDatabasePrivate::insertStudy(const ctkDICOMDataset& ctkDataset, int dbPatientID) { QString studyInstanceUID(ctkDataset.GetElementAsString(DCM_StudyInstanceUID) ); @@ -670,6 +671,7 @@ void ctkDICOMDatabasePrivate::insertStudy(const ctkDICOMDataset& ctkDataset, int } } +//------------------------------------------------------------------------------ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QString studyInstanceUID) { QString seriesInstanceUID(ctkDataset.GetElementAsString(DCM_SeriesInstanceUID) ); @@ -721,6 +723,7 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS } } +//------------------------------------------------------------------------------ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile, bool generateThumbnail) { Q_Q(ctkDICOMDatabase); @@ -912,6 +915,7 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q } } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::fileExistsAndUpToDate(const QString& filePath) { Q_D(ctkDICOMDatabase); @@ -933,18 +937,21 @@ bool ctkDICOMDatabase::fileExistsAndUpToDate(const QString& filePath) } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::isOpen() const { Q_D(const ctkDICOMDatabase); return d->Database.isOpen(); } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::isInMemory() const { Q_D(const ctkDICOMDatabase); return d->DatabaseFileName == ":memory:"; } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::removeSeries(const QString& seriesInstanceUID) { Q_D(ctkDICOMDatabase); @@ -1021,6 +1028,7 @@ bool ctkDICOMDatabase::removeSeries(const QString& seriesInstanceUID) return true; } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::cleanup() { Q_D(ctkDICOMDatabase); @@ -1031,6 +1039,7 @@ bool ctkDICOMDatabase::cleanup() return true; } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::removeStudy(const QString& studyInstanceUID) { Q_D(ctkDICOMDatabase); @@ -1057,6 +1066,7 @@ bool ctkDICOMDatabase::removeStudy(const QString& studyInstanceUID) return result; } +//------------------------------------------------------------------------------ bool ctkDICOMDatabase::removePatient(const QString& patientID) { Q_D(ctkDICOMDatabase); @@ -1085,3 +1095,5 @@ bool ctkDICOMDatabase::removePatient(const QString& patientID) d->LastPatientUID = -1; return result; } + + diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 504d44b471..ebe37efbb7 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -189,6 +189,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject Q_INVOKABLE bool initializeTagCache (){}; /// Return the value of a cached tag Q_INVOKABLE QString cachedTag (const QString sopInstanceUID, const QString tag){}; + /// Insert an instance tag's value into to the cache Q_INVOKABLE bool cacheTag (const QString sopInstanceUID, const QString tag, const QString value){}; From 416961d65b58544ae921ddb6a1f2526fbd083f57 Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Wed, 11 Jul 2012 17:21:35 -0400 Subject: [PATCH 003/247] Implement tag caching methods in database --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 79 ++++++++++++++++++++++++++++ Libs/DICOM/Core/ctkDICOMDatabase.h | 8 +-- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index dba4cc38c4..812b4fed8f 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -106,6 +106,9 @@ class ctkDICOMDatabasePrivate /// parallel inserts are not allowed (yet) QMutex insertMutex; + /// tagCache table has been checked to exist + bool TagCacheVerified; + int insertPatient(const ctkDICOMDataset& ctkDataset); void insertStudy(const ctkDICOMDataset& ctkDataset, int dbPatientID); void insertSeries( const ctkDICOMDataset& ctkDataset, QString studyInstanceUID); @@ -119,6 +122,7 @@ ctkDICOMDatabasePrivate::ctkDICOMDatabasePrivate(ctkDICOMDatabase& o): q_ptr(&o) { this->thumbnailGenerator = NULL; this->LastPatientUID = -1; + this->TagCacheVerified = false; } //------------------------------------------------------------------------------ @@ -1096,4 +1100,79 @@ bool ctkDICOMDatabase::removePatient(const QString& patientID) return result; } +/// +/// Code related to the tagCache +/// + +//------------------------------------------------------------------------------ +bool ctkDICOMDatabase::tagCacheExists() +{ + Q_D(ctkDICOMDatabase); + if (d->TagCacheVerified) + { + return true; + } + QSqlQuery cacheExists( d->Database ); + cacheExists.prepare("SELECT * FROM TagCache LIMIT 1"); + bool success = d->loggedExec(cacheExists); + if (success) + { + d->TagCacheVerified = true; + } + return false; +} + +//------------------------------------------------------------------------------ +bool ctkDICOMDatabase::initializeTagCache() +{ + Q_D(ctkDICOMDatabase); + + // First, drop any existing table + if ( this->tagCacheExists() ) + { + QSqlQuery dropCacheTable( d->Database ); + dropCacheTable.prepare( "DROP TABLE TagCache" ); + d->loggedExec(dropCacheTable); + } + // now create a table + QSqlQuery createCacheTable( d->Database ); + createCacheTable.prepare( + "CREATE TABLE TagCache (SOPInstanceUID, Tag, Value, PRIMARY KEY (SOPInstanceUID, Tag))" ); + bool success = d->loggedExec(createCacheTable); + if (success) + { + d->TagCacheVerified = true; + return true; + } + return false; +} + +//------------------------------------------------------------------------------ +QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString tag) +{ + Q_D(ctkDICOMDatabase); + QSqlQuery selectValue( d->Database ); + selectValue.prepare( "SELECT Value FROM TagCache WHERE SOPInstanceUID = :sopInstanceUID AND Tag = :tag" ); + selectValue.bindValue(":sopInstanceUID",sopInstanceUID); + selectValue.bindValue(":tag",tag); + d->loggedExec(selectValue); + QString result(""); + if (selectValue.next()) + { + result = selectValue.value(0).toString(); + } + return( result ); +} + +//------------------------------------------------------------------------------ +bool ctkDICOMDatabase::cacheTag(const QString sopInstanceUID, const QString tag, const QString value) +{ + Q_D(ctkDICOMDatabase); + QSqlQuery insertTag( d->Database ); + insertTag.prepare( "INSERT OR REPLACE INTO TagCache VALUES(:sopInstanceUID, :tag, :value)" ); + insertTag.bindValue(":sopInstanceUID",sopInstanceUID); + insertTag.bindValue(":tag",tag); + insertTag.bindValue(":value",value); + return d->loggedExec(insertTag); +} diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index ebe37efbb7..6e16de9a0a 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -184,13 +184,13 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject /// @Returns empty string if element for uid is missing from cache /// /// Lightweight check of tag cache existence (once db check per runtime) - Q_INVOKABLE bool tagCacheExists (){}; + Q_INVOKABLE bool tagCacheExists (); /// Create a tagCache in the current database. Delete the existing one if it exists. - Q_INVOKABLE bool initializeTagCache (){}; + Q_INVOKABLE bool initializeTagCache (); /// Return the value of a cached tag - Q_INVOKABLE QString cachedTag (const QString sopInstanceUID, const QString tag){}; + Q_INVOKABLE QString cachedTag (const QString sopInstanceUID, const QString tag); /// Insert an instance tag's value into to the cache - Q_INVOKABLE bool cacheTag (const QString sopInstanceUID, const QString tag, const QString value){}; + Q_INVOKABLE bool cacheTag (const QString sopInstanceUID, const QString tag, const QString value); Q_SIGNALS: From 202821dbf9585518bb04f4b16dd612b7ee2c5e8f Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Thu, 12 Jul 2012 09:38:00 -0400 Subject: [PATCH 004/247] Add tests for tagCache functionality of ctkDICOMDatabase --- .../Testing/Cpp/ctkDICOMDatabaseTest2.cpp | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp index ab75c6d3f2..99a0cb2530 100644 --- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp +++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp @@ -124,6 +124,47 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) return EXIT_FAILURE; } + + // + // Test the tag cache + // + + if (database.tagCacheExists()) + { + std::cerr << "ctkDICOMDatabase: tag cache should not exist in fresh database" << std::endl; + return EXIT_FAILURE; + } + + if (!database.initializeTagCache()) + { + std::cerr << "ctkDICOMDatabase: could not initialize tag cache" << std::endl; + return EXIT_FAILURE; + } + + if (!database.tagCacheExists()) + { + std::cerr << "ctkDICOMDatabase: tag cache should exist but is not detected" << std::endl; + return EXIT_FAILURE; + } + + if (database.cachedTag(instanceUID, tag) != QString("")) + { + std::cerr << "ctkDICOMDatabase: tag cache should return empty string for unknown instance tag" << std::endl; + return EXIT_FAILURE; + } + + if (!database.cacheTag(instanceUID, tag, knownSeriesDescription)) + { + std::cerr << "ctkDICOMDatabase: could not insert instance tag" << std::endl; + return EXIT_FAILURE; + } + + if (database.cachedTag(instanceUID, tag) != knownSeriesDescription) + { + std::cerr << "ctkDICOMDatabase: could not retrieve cached tag" << std::endl; + return EXIT_FAILURE; + } + database.closeDatabase(); database.initializeDatabase(); From 756974e62a4b75880e1e8ba3ad1119082a00b531 Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Thu, 12 Jul 2012 09:39:16 -0400 Subject: [PATCH 005/247] Make database accesses more quiet by default Do not print messages on successful database accesses unless specifically requested. --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 812b4fed8f..492c3b07d3 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -80,6 +80,7 @@ class ctkDICOMDatabasePrivate /// bool loggedExec(QSqlQuery& query); bool loggedExec(QSqlQuery& query, const QString& queryString); + bool LoggedExecVerbose; // dataset must be set always // filePath has to be set if this is an import of an actual file @@ -121,6 +122,7 @@ class ctkDICOMDatabasePrivate ctkDICOMDatabasePrivate::ctkDICOMDatabasePrivate(ctkDICOMDatabase& o): q_ptr(&o) { this->thumbnailGenerator = NULL; + this->LoggedExecVerbose = false; this->LastPatientUID = -1; this->TagCacheVerified = false; } @@ -179,7 +181,10 @@ bool ctkDICOMDatabasePrivate::loggedExec(QSqlQuery& query, const QString& queryS } else { + if (LoggedExecVerbose) + { logger.debug( "SQL worked!\n SQL: " + query.lastQuery()); + } } return (success); } From 796452e3bc5ea872d72d3ed6daa44510a08016e1 Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Thu, 12 Jul 2012 09:47:53 -0400 Subject: [PATCH 006/247] Add utility and tests for tag ushort/string conversion Also expose these as Q_INVOKABLE for use from python. --- Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp | 9 ++++++++- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 6 ++++++ Libs/DICOM/Core/ctkDICOMDatabase.h | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp index 99a0cb2530..845a246c88 100644 --- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp +++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp @@ -97,6 +97,14 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) return EXIT_FAILURE; } + if ( database.groupElementToTag(group, element) != tag ) + { + std::cerr << "ctkDICOMDatabase: could not convert a uints to tag string" << std::endl; + return EXIT_FAILURE; + } + + + // // Basic test: // - insert the file specified on the command line @@ -124,7 +132,6 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) return EXIT_FAILURE; } - // // Test the tag cache // diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 492c3b07d3..e4d1d88b9e 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -533,6 +533,12 @@ bool ctkDICOMDatabase::tagToGroupElement(const QString tag, unsigned short& grou return( groupOK && elementOK ); } +//------------------------------------------------------------------------------ +QString ctkDICOMDatabase::groupElementToTag(const unsigned short& group, const unsigned short& element) +{ + return QString("%1,%2").arg(group,4,16,QLatin1Char('0')).arg(element,4,16,QLatin1Char('0')); +} + //------------------------------------------------------------------------------ void ctkDICOMDatabase::insert( DcmDataset *dataset, bool storeFile, bool generateThumbnail) { diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 6e16de9a0a..63a0dc6234 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -171,7 +171,8 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject Q_INVOKABLE QString instanceValue (const QString sopInstanceUID, const unsigned short group, const unsigned short element); Q_INVOKABLE QString fileValue (const QString fileName, const QString tag); Q_INVOKABLE QString fileValue (const QString fileName, const unsigned short group, const unsigned short element); - bool tagToGroupElement (const QString tag, unsigned short& group, unsigned short& element); + Q_INVOKABLE bool tagToGroupElement (const QString tag, unsigned short& group, unsigned short& element); + Q_INVOKABLE QString groupElementToTag (const unsigned short& group, const unsigned short& element); /// /// \brief store values of previously requested instance elements From 8dad059d2b15e4154728db0c7b600f21b14ac296 Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Thu, 12 Jul 2012 10:36:40 -0400 Subject: [PATCH 007/247] Add cached accessors and helper methods Should improve performance for multiple accesses to the same element values in different parts of the code and accross runs of the application. --- .../Testing/Cpp/ctkDICOMDatabaseTest2.cpp | 19 ++++-- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 65 ++++++++++++++++++- Libs/DICOM/Core/ctkDICOMDatabase.h | 1 + 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp index 845a246c88..ddd71d9b83 100644 --- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp +++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp @@ -67,11 +67,11 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) { std::cerr << "ctkDICOMDatabase::openDatabase() failed: " << "database should not be in memory" << std::endl; - return EXIT_FAILURE; + return EXIT_FAILURE; } bool res = database.initializeDatabase(); - + if (!res) { std::cerr << "ctkDICOMDatabase::initializeDatabase() failed." << std::endl; @@ -104,7 +104,6 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) } - // // Basic test: // - insert the file specified on the command line @@ -120,7 +119,15 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) std::cerr << "ctkDICOMDatabase: didn't get back the original file path" << std::endl; return EXIT_FAILURE; } - + + QString foundInstance = database.instanceForFile(dicomFilePath); + + if (foundInstance != instanceUID) + { + std::cerr << "ctkDICOMDatabase: didn't get back the original instance uid" << std::endl; + return EXIT_FAILURE; + } + QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE"); @@ -160,13 +167,13 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) return EXIT_FAILURE; } - if (!database.cacheTag(instanceUID, tag, knownSeriesDescription)) + if (!database.cacheTag(instanceUID, tag, knownSeriesDescription)) { std::cerr << "ctkDICOMDatabase: could not insert instance tag" << std::endl; return EXIT_FAILURE; } - if (database.cachedTag(instanceUID, tag) != knownSeriesDescription) + if (database.cachedTag(instanceUID, tag) != knownSeriesDescription) { std::cerr << "ctkDICOMDatabase: could not retrieve cached tag" << std::endl; return EXIT_FAILURE; diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index e4d1d88b9e..db57993151 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -335,6 +335,10 @@ void ctkDICOMDatabase::closeDatabase() d->Database.close(); } +// +// Patient/study/series convenience methods +// + //------------------------------------------------------------------------------ QStringList ctkDICOMDatabase::patients() { @@ -407,13 +411,33 @@ QString ctkDICOMDatabase::fileForInstance(QString sopInstanceUID) query.bindValue ( 0, sopInstanceUID ); query.exec(); QString result; - if (query.next()) + if (query.next()) + { + result = query.value(0).toString(); + } + return( result ); +} + +//------------------------------------------------------------------------------ +QString ctkDICOMDatabase::instanceForFile(QString fileName) +{ + Q_D(ctkDICOMDatabase); + QSqlQuery query(d->Database); + query.prepare ( "SELECT SOPInstanceUID FROM Images WHERE Filename=?"); + query.bindValue ( 0, fileName ); + query.exec(); + QString result; + if (query.next()) { result = query.value(0).toString(); } return( result ); } +// +// instance header methods +// + //------------------------------------------------------------------------------ void ctkDICOMDatabase::loadInstanceHeader (QString sopInstanceUID) { @@ -469,9 +493,18 @@ QString ctkDICOMDatabase::headerValue (QString key) return (d->LoadedHeader[key]); } +// +// instanceValue and fileValue methods +// + //------------------------------------------------------------------------------ QString ctkDICOMDatabase::instanceValue(QString sopInstanceUID, QString tag) { + QString value = this->cachedTag(sopInstanceUID, tag); + if (value != "") + { + return value; + } unsigned short group, element; this->tagToGroupElement(tag, group, element); return( this->instanceValue(sopInstanceUID, group, element) ); @@ -480,6 +513,12 @@ QString ctkDICOMDatabase::instanceValue(QString sopInstanceUID, QString tag) //------------------------------------------------------------------------------ QString ctkDICOMDatabase::instanceValue(const QString sopInstanceUID, const unsigned short group, const unsigned short element) { + QString tag = this->groupElementToTag(group,element); + QString value = this->cachedTag(sopInstanceUID, tag); + if (value != "") + { + return value; + } QString filePath = this->fileForInstance(sopInstanceUID); if (filePath != "" ) { @@ -497,6 +536,12 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, QString tag) { unsigned short group, element; this->tagToGroupElement(tag, group, element); + QString sopInstanceUID = this->instanceForFile(fileName); + QString value = this->cachedTag(sopInstanceUID, tag); + if (value != "") + { + return value; + } return( this->fileValue(fileName, group, element) ); } @@ -504,6 +549,8 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, QString tag) QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short group, const unsigned short element) { // here is where the real lookup happens + // - first we check the tagCache to see if the value exists for this instance tag + // If not, // - for now we create a ctkDICOMDataset and extract the value from there // - then we convert to the appropriate type of string // @@ -514,9 +561,17 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short // -- if so, keep looking for the requested group/element // -- if not, start again from the begining + QString tag = this->groupElementToTag(group, element); + QString sopInstanceUID = this->instanceForFile(fileName); + QString value = this->cachedTag(sopInstanceUID, tag); + if (value != "") + { + return value; + } + ctkDICOMDataset dataset; dataset.InitializeFromFile(fileName); - + DcmTagKey tagKey(group, element); return( dataset.GetAllElementValuesAsString(tagKey) ); @@ -539,6 +594,10 @@ QString ctkDICOMDatabase::groupElementToTag(const unsigned short& group, const u return QString("%1,%2").arg(group,4,16,QLatin1Char('0')).arg(element,4,16,QLatin1Char('0')); } +// +// methods related to insert +// + //------------------------------------------------------------------------------ void ctkDICOMDatabase::insert( DcmDataset *dataset, bool storeFile, bool generateThumbnail) { @@ -1169,7 +1228,7 @@ QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString selectValue.bindValue(":tag",tag); d->loggedExec(selectValue); QString result(""); - if (selectValue.next()) + if (selectValue.next()) { result = selectValue.value(0).toString(); } diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 63a0dc6234..e6f25366ec 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -117,6 +117,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject Q_INVOKABLE QStringList seriesForStudy (const QString studyUID); Q_INVOKABLE QStringList filesForSeries (const QString seriesUID); Q_INVOKABLE QString fileForInstance (const QString sopInstanceUID); + Q_INVOKABLE QString instanceForFile (const QString fileName); /// /// \brief load the header from a file and allow access to elements From 750410a8bf56e122e0d38f2deee979e5f9af2e8f Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Fri, 13 Jul 2012 22:45:01 +0200 Subject: [PATCH 008/247] Added new method to get all files in database --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 20 +++++++++++++++++++- Libs/DICOM/Core/ctkDICOMDatabase.h | 1 + 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 12c4664ce2..1b01eed8b8 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -398,13 +398,31 @@ QString ctkDICOMDatabase::fileForInstance(QString sopInstanceUID) query.bindValue ( 0, sopInstanceUID ); query.exec(); QString result; - if (query.next()) + if (query.next()) { result = query.value(0).toString(); } return( result ); } +//------------------------------------------------------------------------------ +QStringList ctkDICOMDatabase::allFiles() +{ + Q_D(ctkDICOMDatabase); + + /// get all filenames from the database + QSqlQuery allFilesQuery(d->Database); + QStringList allFileNames; + allFilesQuery.prepare("SELECT Filename from Images;"); + allFilesQuery.exec(); + + while (allFilesQuery.next()) + { + allFileNames << allFilesQuery.value(0).toString(); + } + return allFileNames; +} + //------------------------------------------------------------------------------ void ctkDICOMDatabase::loadInstanceHeader (QString sopInstanceUID) { diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 299f47c107..e28f9f4743 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -118,6 +118,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject Q_INVOKABLE QStringList filesForSeries (const QString seriesUID); Q_INVOKABLE QString fileForInstance (const QString sopInstanceUID); + Q_INVOKABLE QStringList allFiles (); /// /// \brief load the header from a file and allow access to elements /// @param sopInstanceUID A string with the uid for a given instance From 3e5fdc1af215b98e2b08d42b5708ec8ca68ad9eb Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Fri, 13 Jul 2012 22:45:19 +0200 Subject: [PATCH 009/247] Style fixed --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 1b01eed8b8..3b19eabd5a 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -525,7 +525,7 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short ctkDICOMDataset dataset; dataset.InitializeFromFile(fileName); - + DcmTagKey tagKey(group, element); return( dataset.GetAllElementValuesAsString(tagKey) ); From b4c33cebd2ab1da90e18bedc1b539815bf823a53 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Fri, 13 Jul 2012 23:28:57 +0200 Subject: [PATCH 010/247] New internal method to create a backup filelist This could be used e.g. for reindexing everything with a new database schema. --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 3b19eabd5a..fe7f8307d3 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -85,6 +85,10 @@ class ctkDICOMDatabasePrivate // filePath has to be set if this is an import of an actual file void insert ( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile = true, bool generateThumbnail = true); + /// + /// copy the complete list of files to an extra table + /// + void createBackupFileList(); /// Name of the database file (i.e. for SQLITE the sqlite file) QString DatabaseFileName; @@ -180,6 +184,15 @@ bool ctkDICOMDatabasePrivate::loggedExec(QSqlQuery& query, const QString& queryS return (success); } +//------------------------------------------------------------------------------ +void ctkDICOMDatabasePrivate::createBackupFileList() +{ + QSqlQuery query(this->Database); + loggedExec(query, "CREATE TABLE IF NOT EXISTS main.Filenames_backup (Filename TEXT PRIMARY KEY NOT NULL )" ); + loggedExec(query, "INSERT INTO Filenames_backup SELECT Filename FROM Images;" ); +} + + //------------------------------------------------------------------------------ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& connectionName ) { From 273e21d3b86d5ac4b825ec526530fd5c0774acab Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Fri, 13 Jul 2012 17:48:24 -0400 Subject: [PATCH 011/247] Rename ctkDICOMIndexerPrivate.h into ctkDICOMIndexerPrivate_p. See issue #191 --- Libs/DICOM/Core/CMakeLists.txt | 4 ++-- Libs/DICOM/Core/ctkDICOMIndexer.cpp | 2 +- .../Core/{ctkDICOMIndexerPrivate.h => ctkDICOMIndexer_p.h} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename Libs/DICOM/Core/{ctkDICOMIndexerPrivate.h => ctkDICOMIndexer_p.h} (100%) diff --git a/Libs/DICOM/Core/CMakeLists.txt b/Libs/DICOM/Core/CMakeLists.txt index bceaa3a9d9..cfd5c92d48 100644 --- a/Libs/DICOM/Core/CMakeLists.txt +++ b/Libs/DICOM/Core/CMakeLists.txt @@ -19,7 +19,7 @@ set(KIT_SRCS ctkDICOMFilterProxyModel.h ctkDICOMIndexer.cpp ctkDICOMIndexer.h - ctkDICOMIndexerPrivate.h + ctkDICOMIndexer_p.h ctkDICOMModel.cpp ctkDICOMModel.h ctkDICOMPersonName.cpp @@ -43,7 +43,7 @@ set(KIT_MOC_SRCS ctkDICOMAbstractThumbnailGenerator.h ctkDICOMDatabase.h ctkDICOMIndexer.h - ctkDICOMIndexerPrivate.h + ctkDICOMIndexer_p.h ctkDICOMFilterProxyModel.h ctkDICOMModel.h ctkDICOMQuery.h diff --git a/Libs/DICOM/Core/ctkDICOMIndexer.cpp b/Libs/DICOM/Core/ctkDICOMIndexer.cpp index 84cea37c51..678b563ce4 100644 --- a/Libs/DICOM/Core/ctkDICOMIndexer.cpp +++ b/Libs/DICOM/Core/ctkDICOMIndexer.cpp @@ -36,7 +36,7 @@ // ctkDICOM includes #include "ctkLogger.h" #include "ctkDICOMIndexer.h" -#include "ctkDICOMIndexerPrivate.h" +#include "ctkDICOMIndexer_p.h" #include "ctkDICOMDatabase.h" // DCMTK includes diff --git a/Libs/DICOM/Core/ctkDICOMIndexerPrivate.h b/Libs/DICOM/Core/ctkDICOMIndexer_p.h similarity index 100% rename from Libs/DICOM/Core/ctkDICOMIndexerPrivate.h rename to Libs/DICOM/Core/ctkDICOMIndexer_p.h From 229714a4e2e38fb6fc2e6d8061e4f9ca156cf988 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Fri, 13 Jul 2012 17:48:50 -0400 Subject: [PATCH 012/247] Rename "*Private.(h|tpp|cpp)" into "*_p.(h|tpp|cpp)" All headers, cpp and tpp files are now consistently named across the toolkit. This is also consistent with Qt naming convention. Close issue #191 --- Libs/PluginFramework/CMakeLists.txt | 20 +++++++++---------- Libs/PluginFramework/ctkLDAPSearchFilter.cpp | 2 +- Libs/PluginFramework/ctkPlugin.cpp | 7 +++---- Libs/PluginFramework/ctkPluginContext.cpp | 6 +++--- Libs/PluginFramework/ctkPluginFramework.cpp | 9 ++++----- .../ctkPluginFrameworkContext.cpp | 3 +-- .../ctkPluginFrameworkListeners.cpp | 2 +- ...rkPrivate.cpp => ctkPluginFramework_p.cpp} | 5 ++--- ...workPrivate_p.h => ctkPluginFramework_p.h} | 6 +++--- Libs/PluginFramework/ctkPluginTracker.tpp | 2 +- ...nTrackerPrivate.h => ctkPluginTracker_p.h} | 2 +- ...ckerPrivate.tpp => ctkPluginTracker_p.tpp} | 0 .../{ctkPluginPrivate.cpp => ctkPlugin_p.cpp} | 7 +++---- .../{ctkPluginPrivate_p.h => ctkPlugin_p.h} | 0 Libs/PluginFramework/ctkPlugins.cpp | 7 +++---- Libs/PluginFramework/ctkRequirePlugin.cpp | 5 ++--- Libs/PluginFramework/ctkServiceReference.cpp | 12 +++++------ ...ePrivate.cpp => ctkServiceReference_p.cpp} | 9 ++++----- ...rencePrivate.h => ctkServiceReference_p.h} | 0 .../ctkServiceRegistration.cpp | 13 ++++++------ ...ivate.cpp => ctkServiceRegistration_p.cpp} | 2 +- ...onPrivate.h => ctkServiceRegistration_p.h} | 0 Libs/PluginFramework/ctkServiceTracker.tpp | 2 +- ...TrackerPrivate.h => ctkServiceTracker_p.h} | 2 +- ...kerPrivate.tpp => ctkServiceTracker_p.tpp} | 0 Libs/PluginFramework/ctkServices.cpp | 2 +- Libs/PluginFramework/ctkServices_p.h | 2 +- 27 files changed, 59 insertions(+), 68 deletions(-) rename Libs/PluginFramework/{ctkPluginFrameworkPrivate.cpp => ctkPluginFramework_p.cpp} (99%) rename Libs/PluginFramework/{ctkPluginFrameworkPrivate_p.h => ctkPluginFramework_p.h} (99%) rename Libs/PluginFramework/{ctkPluginTrackerPrivate.h => ctkPluginTracker_p.h} (98%) rename Libs/PluginFramework/{ctkPluginTrackerPrivate.tpp => ctkPluginTracker_p.tpp} (100%) rename Libs/PluginFramework/{ctkPluginPrivate.cpp => ctkPlugin_p.cpp} (99%) rename Libs/PluginFramework/{ctkPluginPrivate_p.h => ctkPlugin_p.h} (100%) rename Libs/PluginFramework/{ctkServiceReferencePrivate.cpp => ctkServiceReference_p.cpp} (98%) rename Libs/PluginFramework/{ctkServiceReferencePrivate.h => ctkServiceReference_p.h} (100%) rename Libs/PluginFramework/{ctkServiceRegistrationPrivate.cpp => ctkServiceRegistration_p.cpp} (97%) rename Libs/PluginFramework/{ctkServiceRegistrationPrivate.h => ctkServiceRegistration_p.h} (100%) rename Libs/PluginFramework/{ctkServiceTrackerPrivate.h => ctkServiceTracker_p.h} (99%) rename Libs/PluginFramework/{ctkServiceTrackerPrivate.tpp => ctkServiceTracker_p.tpp} (100%) diff --git a/Libs/PluginFramework/CMakeLists.txt b/Libs/PluginFramework/CMakeLists.txt index c2a0710d70..805a5128d8 100644 --- a/Libs/PluginFramework/CMakeLists.txt +++ b/Libs/PluginFramework/CMakeLists.txt @@ -39,15 +39,15 @@ set(KIT_SRCS ctkPluginFrameworkLauncher.cpp ctkPluginFrameworkListeners.cpp ctkPluginFrameworkListeners_p.h - ctkPluginFrameworkPrivate.cpp - ctkPluginFrameworkPrivate_p.h + ctkPluginFramework_p.cpp + ctkPluginFramework_p.h ctkPluginFrameworkUtil.cpp ctkPluginFrameworkUtil_p.h ctkPluginLocalization.cpp ctkPluginManifest.cpp ctkPluginManifest_p.h - ctkPluginPrivate.cpp - ctkPluginPrivate_p.h + ctkPlugin_p.cpp + ctkPlugin_p.h ctkPlugins.cpp ctkPlugins_p.h ctkPluginStorage_p.h @@ -55,17 +55,17 @@ set(KIT_SRCS ctkPluginStorageSQL_p.h ctkPluginTracker.h ctkPluginTracker.tpp - ctkPluginTrackerPrivate.h - ctkPluginTrackerPrivate.tpp + ctkPluginTracker_p.h + ctkPluginTracker_p.tpp ctkRequirePlugin.cpp ctkRequirePlugin_p.h ctkServiceEvent.cpp ctkServiceException.cpp ctkServiceFactory.h ctkServiceReference.cpp - ctkServiceReferencePrivate.cpp + ctkServiceReference_p.cpp ctkServiceRegistration.cpp - ctkServiceRegistrationPrivate.cpp + ctkServiceRegistration_p.cpp ctkServices.cpp ctkServices_p.h ctkServiceSlotEntry.cpp @@ -73,8 +73,8 @@ set(KIT_SRCS ctkServiceTracker.h ctkServiceTracker.tpp ctkServiceTrackerCustomizer.h - ctkServiceTrackerPrivate.h - ctkServiceTrackerPrivate.tpp + ctkServiceTracker_p.h + ctkServiceTracker_p.tpp ctkTrackedPlugin_p.h ctkTrackedPlugin.tpp ctkTrackedPluginListener_p.h diff --git a/Libs/PluginFramework/ctkLDAPSearchFilter.cpp b/Libs/PluginFramework/ctkLDAPSearchFilter.cpp index d3e549f779..5bd68f6cfc 100644 --- a/Libs/PluginFramework/ctkLDAPSearchFilter.cpp +++ b/Libs/PluginFramework/ctkLDAPSearchFilter.cpp @@ -22,7 +22,7 @@ #include "ctkLDAPSearchFilter.h" #include "ctkLDAPExpr_p.h" -#include "ctkServiceReferencePrivate.h" +#include "ctkServiceReference_p.h" //---------------------------------------------------------------------------- class ctkLDAPSearchFilterData : public QSharedData diff --git a/Libs/PluginFramework/ctkPlugin.cpp b/Libs/PluginFramework/ctkPlugin.cpp index 00c4d39592..51aed709e8 100644 --- a/Libs/PluginFramework/ctkPlugin.cpp +++ b/Libs/PluginFramework/ctkPlugin.cpp @@ -19,19 +19,18 @@ =============================================================================*/ -#include "ctkPlugin.h" +#include +#include "ctkPlugin.h" +#include "ctkPlugin_p.h" #include "ctkPluginContext.h" #include "ctkPluginContext_p.h" #include "ctkPluginFrameworkUtil_p.h" -#include "ctkPluginPrivate_p.h" #include "ctkPluginArchive_p.h" #include "ctkPluginFrameworkContext_p.h" #include "ctkServices_p.h" #include "ctkUtils.h" -#include - //---------------------------------------------------------------------------- ctkPlugin::ctkPlugin() : d_ptr(0) diff --git a/Libs/PluginFramework/ctkPluginContext.cpp b/Libs/PluginFramework/ctkPluginContext.cpp index 629bfd997d..abe2219626 100644 --- a/Libs/PluginFramework/ctkPluginContext.cpp +++ b/Libs/PluginFramework/ctkPluginContext.cpp @@ -19,15 +19,15 @@ =============================================================================*/ +#include "ctkPlugin_p.h" #include "ctkPluginContext.h" #include "ctkPluginContext_p.h" - -#include "ctkPluginPrivate_p.h" #include "ctkPluginFrameworkContext_p.h" + #include "ctkServices_p.h" #include "ctkServiceRegistration.h" #include "ctkServiceReference.h" -#include "ctkServiceReferencePrivate.h" +#include "ctkServiceReference_p.h" #include diff --git a/Libs/PluginFramework/ctkPluginFramework.cpp b/Libs/PluginFramework/ctkPluginFramework.cpp index 070feaaca7..de030e0de5 100644 --- a/Libs/PluginFramework/ctkPluginFramework.cpp +++ b/Libs/PluginFramework/ctkPluginFramework.cpp @@ -19,13 +19,12 @@ =============================================================================*/ +#include "ctkPlugin_p.h" +#include "ctkPluginArchive_p.h" +#include "ctkPluginConstants.h" #include "ctkPluginFramework.h" - -#include "ctkPluginFrameworkPrivate_p.h" -#include "ctkPluginPrivate_p.h" +#include "ctkPluginFramework_p.h" #include "ctkPluginFrameworkContext_p.h" -#include "ctkPluginConstants.h" -#include "ctkPluginArchive_p.h" #include "service/event/ctkEvent.h" diff --git a/Libs/PluginFramework/ctkPluginFrameworkContext.cpp b/Libs/PluginFramework/ctkPluginFrameworkContext.cpp index 9c9ce1dcb1..17a39f04f7 100644 --- a/Libs/PluginFramework/ctkPluginFrameworkContext.cpp +++ b/Libs/PluginFramework/ctkPluginFrameworkContext.cpp @@ -20,9 +20,8 @@ =============================================================================*/ #include "ctkPluginFrameworkContext_p.h" - #include "ctkPluginFrameworkUtil_p.h" -#include "ctkPluginFrameworkPrivate_p.h" +#include "ctkPluginFramework_p.h" #include "ctkPluginArchive_p.h" #include "ctkPluginStorageSQL_p.h" #include "ctkPluginConstants.h" diff --git a/Libs/PluginFramework/ctkPluginFrameworkListeners.cpp b/Libs/PluginFramework/ctkPluginFrameworkListeners.cpp index 9d15e679d8..c20133297a 100644 --- a/Libs/PluginFramework/ctkPluginFrameworkListeners.cpp +++ b/Libs/PluginFramework/ctkPluginFrameworkListeners.cpp @@ -25,7 +25,7 @@ #include "ctkPluginFrameworkContext_p.h" #include "ctkPluginConstants.h" #include "ctkLDAPExpr_p.h" -#include "ctkServiceReferencePrivate.h" +#include "ctkServiceReference_p.h" #include #include diff --git a/Libs/PluginFramework/ctkPluginFrameworkPrivate.cpp b/Libs/PluginFramework/ctkPluginFramework_p.cpp similarity index 99% rename from Libs/PluginFramework/ctkPluginFrameworkPrivate.cpp rename to Libs/PluginFramework/ctkPluginFramework_p.cpp index f3db994ffa..6b8e084597 100644 --- a/Libs/PluginFramework/ctkPluginFrameworkPrivate.cpp +++ b/Libs/PluginFramework/ctkPluginFramework_p.cpp @@ -19,12 +19,11 @@ =============================================================================*/ -#include "ctkPluginFrameworkPrivate_p.h" - -#include "ctkPluginFramework.h" #include "ctkPluginConstants.h" #include "ctkPluginContext.h" #include "ctkPluginContext_p.h" +#include "ctkPluginFramework.h" +#include "ctkPluginFramework_p.h" #include "ctkPluginFrameworkContext_p.h" #include "ctkPluginFrameworkUtil_p.h" diff --git a/Libs/PluginFramework/ctkPluginFrameworkPrivate_p.h b/Libs/PluginFramework/ctkPluginFramework_p.h similarity index 99% rename from Libs/PluginFramework/ctkPluginFrameworkPrivate_p.h rename to Libs/PluginFramework/ctkPluginFramework_p.h index fe38473a7e..148f0d65e7 100644 --- a/Libs/PluginFramework/ctkPluginFrameworkPrivate_p.h +++ b/Libs/PluginFramework/ctkPluginFramework_p.h @@ -22,11 +22,11 @@ #ifndef CTKPLUGINFRAMEWORKPRIVATE_P_H #define CTKPLUGINFRAMEWORKPRIVATE_P_H -#include "ctkPluginPrivate_p.h" -#include "ctkPluginFramework.h" - #include +#include "ctkPlugin_p.h" +#include "ctkPluginFramework.h" + class ctkPluginFrameworkContext; /** diff --git a/Libs/PluginFramework/ctkPluginTracker.tpp b/Libs/PluginFramework/ctkPluginTracker.tpp index 24225ca87d..e760da5fa0 100644 --- a/Libs/PluginFramework/ctkPluginTracker.tpp +++ b/Libs/PluginFramework/ctkPluginTracker.tpp @@ -21,7 +21,7 @@ #include "ctkPluginContext.h" -#include "ctkPluginTrackerPrivate.h" +#include "ctkPluginTracker_p.h" #include "ctkTrackedPlugin_p.h" #include diff --git a/Libs/PluginFramework/ctkPluginTrackerPrivate.h b/Libs/PluginFramework/ctkPluginTracker_p.h similarity index 98% rename from Libs/PluginFramework/ctkPluginTrackerPrivate.h rename to Libs/PluginFramework/ctkPluginTracker_p.h index 0be3193233..44a092d31a 100644 --- a/Libs/PluginFramework/ctkPluginTrackerPrivate.h +++ b/Libs/PluginFramework/ctkPluginTracker_p.h @@ -94,6 +94,6 @@ class ctkPluginTrackerPrivate ctkPluginTracker * const q_ptr; }; -#include "ctkPluginTrackerPrivate.tpp" +#include "ctkPluginTracker_p.tpp" #endif // CTKPLUGINTRACKERPRIVATE_H diff --git a/Libs/PluginFramework/ctkPluginTrackerPrivate.tpp b/Libs/PluginFramework/ctkPluginTracker_p.tpp similarity index 100% rename from Libs/PluginFramework/ctkPluginTrackerPrivate.tpp rename to Libs/PluginFramework/ctkPluginTracker_p.tpp diff --git a/Libs/PluginFramework/ctkPluginPrivate.cpp b/Libs/PluginFramework/ctkPlugin_p.cpp similarity index 99% rename from Libs/PluginFramework/ctkPluginPrivate.cpp rename to Libs/PluginFramework/ctkPlugin_p.cpp index acfa29f120..df2345f75e 100644 --- a/Libs/PluginFramework/ctkPluginPrivate.cpp +++ b/Libs/PluginFramework/ctkPlugin_p.cpp @@ -19,8 +19,7 @@ =============================================================================*/ -#include "ctkPluginPrivate_p.h" - +#include "ctkPlugin_p.h" #include "ctkPluginConstants.h" #include "ctkPluginDatabaseException.h" #include "ctkPluginArchive_p.h" @@ -29,9 +28,9 @@ #include "ctkPluginActivator.h" #include "ctkPluginContext_p.h" -#include "ctkServices_p.h" -#include "ctkServiceReferencePrivate.h" +#include "ctkServiceReference_p.h" #include "ctkServiceRegistration.h" +#include "ctkServices_p.h" // for ctk::msecsTo() - remove after switching to Qt 4.7 #include diff --git a/Libs/PluginFramework/ctkPluginPrivate_p.h b/Libs/PluginFramework/ctkPlugin_p.h similarity index 100% rename from Libs/PluginFramework/ctkPluginPrivate_p.h rename to Libs/PluginFramework/ctkPlugin_p.h diff --git a/Libs/PluginFramework/ctkPlugins.cpp b/Libs/PluginFramework/ctkPlugins.cpp index 57e423a82e..c79c6133c9 100644 --- a/Libs/PluginFramework/ctkPlugins.cpp +++ b/Libs/PluginFramework/ctkPlugins.cpp @@ -19,19 +19,18 @@ =============================================================================*/ -#include "ctkPlugins_p.h" +#include -#include "ctkPluginPrivate_p.h" +#include "ctkPlugin_p.h" #include "ctkPluginArchive_p.h" #include "ctkPluginException.h" #include "ctkPluginFrameworkContext_p.h" +#include "ctkPlugins_p.h" #include "ctkVersionRange_p.h" #include #include -#include - //---------------------------------------------------------------------------- void ctkPlugins::checkIllegalState() const { diff --git a/Libs/PluginFramework/ctkRequirePlugin.cpp b/Libs/PluginFramework/ctkRequirePlugin.cpp index 1ec3b72253..ca1ea1d88c 100644 --- a/Libs/PluginFramework/ctkRequirePlugin.cpp +++ b/Libs/PluginFramework/ctkRequirePlugin.cpp @@ -19,10 +19,9 @@ =============================================================================*/ -#include "ctkRequirePlugin_p.h" - +#include "ctkPlugin_p.h" #include "ctkPluginConstants.h" -#include "ctkPluginPrivate_p.h" +#include "ctkRequirePlugin_p.h" //---------------------------------------------------------------------------- ctkRequirePlugin::ctkRequirePlugin(ctkPluginPrivate* requestor, diff --git a/Libs/PluginFramework/ctkServiceReference.cpp b/Libs/PluginFramework/ctkServiceReference.cpp index 7ba29774ac..470431f0de 100644 --- a/Libs/PluginFramework/ctkServiceReference.cpp +++ b/Libs/PluginFramework/ctkServiceReference.cpp @@ -19,16 +19,16 @@ =============================================================================*/ -#include "ctkServiceReference.h" -#include "ctkServiceReferencePrivate.h" -#include "ctkServiceRegistrationPrivate.h" -#include "ctkPluginPrivate_p.h" -#include "ctkPluginConstants.h" - #include #include #include +#include "ctkPlugin_p.h" +#include "ctkPluginConstants.h" +#include "ctkServiceReference.h" +#include "ctkServiceReference_p.h" +#include "ctkServiceRegistration_p.h" + //---------------------------------------------------------------------------- ctkServiceReference::ctkServiceReference() : d_ptr(new ctkServiceReferencePrivate(0)) diff --git a/Libs/PluginFramework/ctkServiceReferencePrivate.cpp b/Libs/PluginFramework/ctkServiceReference_p.cpp similarity index 98% rename from Libs/PluginFramework/ctkServiceReferencePrivate.cpp rename to Libs/PluginFramework/ctkServiceReference_p.cpp index 1a6da252e1..e780003926 100644 --- a/Libs/PluginFramework/ctkServiceReferencePrivate.cpp +++ b/Libs/PluginFramework/ctkServiceReference_p.cpp @@ -19,19 +19,18 @@ =============================================================================*/ -#include "ctkServiceReferencePrivate.h" +#include "ctkServiceReference_p.h" #include #include +#include "ctkPlugin_p.h" #include "ctkPluginConstants.h" +#include "ctkPluginFrameworkContext_p.h" #include "ctkServiceFactory.h" #include "ctkServiceException.h" -#include "ctkPluginPrivate_p.h" - #include "ctkServices_p.h" -#include "ctkServiceRegistrationPrivate.h" -#include "ctkPluginFrameworkContext_p.h" +#include "ctkServiceRegistration_p.h" //---------------------------------------------------------------------------- ctkServiceReferencePrivate::ctkServiceReferencePrivate(ctkServiceRegistrationPrivate* reg) diff --git a/Libs/PluginFramework/ctkServiceReferencePrivate.h b/Libs/PluginFramework/ctkServiceReference_p.h similarity index 100% rename from Libs/PluginFramework/ctkServiceReferencePrivate.h rename to Libs/PluginFramework/ctkServiceReference_p.h diff --git a/Libs/PluginFramework/ctkServiceRegistration.cpp b/Libs/PluginFramework/ctkServiceRegistration.cpp index 96dd8dc65f..4df89a4ea4 100644 --- a/Libs/PluginFramework/ctkServiceRegistration.cpp +++ b/Libs/PluginFramework/ctkServiceRegistration.cpp @@ -19,18 +19,17 @@ =============================================================================*/ -#include "ctkServiceRegistration.h" -#include "ctkServiceRegistrationPrivate.h" +#include + #include "ctkPluginFrameworkContext_p.h" -#include "ctkPluginPrivate_p.h" +#include "ctkPlugin_p.h" #include "ctkPluginConstants.h" - -#include "ctkServices_p.h" #include "ctkServiceFactory.h" +#include "ctkServiceRegistration.h" +#include "ctkServiceRegistration_p.h" +#include "ctkServices_p.h" #include "ctkServiceSlotEntry_p.h" -#include - #include //---------------------------------------------------------------------------- diff --git a/Libs/PluginFramework/ctkServiceRegistrationPrivate.cpp b/Libs/PluginFramework/ctkServiceRegistration_p.cpp similarity index 97% rename from Libs/PluginFramework/ctkServiceRegistrationPrivate.cpp rename to Libs/PluginFramework/ctkServiceRegistration_p.cpp index 582808c97a..ab8a0e0932 100644 --- a/Libs/PluginFramework/ctkServiceRegistrationPrivate.cpp +++ b/Libs/PluginFramework/ctkServiceRegistration_p.cpp @@ -19,7 +19,7 @@ =============================================================================*/ -#include "ctkServiceRegistrationPrivate.h" +#include "ctkServiceRegistration_p.h" //---------------------------------------------------------------------------- ctkServiceRegistrationPrivate::ctkServiceRegistrationPrivate( diff --git a/Libs/PluginFramework/ctkServiceRegistrationPrivate.h b/Libs/PluginFramework/ctkServiceRegistration_p.h similarity index 100% rename from Libs/PluginFramework/ctkServiceRegistrationPrivate.h rename to Libs/PluginFramework/ctkServiceRegistration_p.h diff --git a/Libs/PluginFramework/ctkServiceTracker.tpp b/Libs/PluginFramework/ctkServiceTracker.tpp index 8bf2abe0f8..2a243acc0f 100644 --- a/Libs/PluginFramework/ctkServiceTracker.tpp +++ b/Libs/PluginFramework/ctkServiceTracker.tpp @@ -20,7 +20,7 @@ =============================================================================*/ -#include "ctkServiceTrackerPrivate.h" +#include "ctkServiceTracker_p.h" #include "ctkTrackedService_p.h" #include "ctkServiceException.h" #include "ctkPluginConstants.h" diff --git a/Libs/PluginFramework/ctkServiceTrackerPrivate.h b/Libs/PluginFramework/ctkServiceTracker_p.h similarity index 99% rename from Libs/PluginFramework/ctkServiceTrackerPrivate.h rename to Libs/PluginFramework/ctkServiceTracker_p.h index 93d41fa9da..8a3751c333 100644 --- a/Libs/PluginFramework/ctkServiceTrackerPrivate.h +++ b/Libs/PluginFramework/ctkServiceTracker_p.h @@ -167,6 +167,6 @@ class ctkServiceTrackerPrivate }; -#include "ctkServiceTrackerPrivate.tpp" +#include "ctkServiceTracker_p.tpp" #endif // CTKSERVICETRACKERPRIVATE_H diff --git a/Libs/PluginFramework/ctkServiceTrackerPrivate.tpp b/Libs/PluginFramework/ctkServiceTracker_p.tpp similarity index 100% rename from Libs/PluginFramework/ctkServiceTrackerPrivate.tpp rename to Libs/PluginFramework/ctkServiceTracker_p.tpp diff --git a/Libs/PluginFramework/ctkServices.cpp b/Libs/PluginFramework/ctkServices.cpp index dccd5b9b5c..4beb41ad6a 100644 --- a/Libs/PluginFramework/ctkServices.cpp +++ b/Libs/PluginFramework/ctkServices.cpp @@ -31,7 +31,7 @@ #include "ctkPluginConstants.h" #include "ctkPluginFrameworkContext_p.h" #include "ctkServiceException.h" -#include "ctkServiceRegistrationPrivate.h" +#include "ctkServiceRegistration_p.h" #include "ctkLDAPExpr_p.h" //---------------------------------------------------------------------------- diff --git a/Libs/PluginFramework/ctkServices_p.h b/Libs/PluginFramework/ctkServices_p.h index d081515fdc..7eab76d73e 100644 --- a/Libs/PluginFramework/ctkServices_p.h +++ b/Libs/PluginFramework/ctkServices_p.h @@ -28,8 +28,8 @@ #include #include +#include "ctkPlugin_p.h" #include "ctkServiceRegistration.h" -#include "ctkPluginPrivate_p.h" /** From 714e6c7ec9af70d90cc45bcf77e7a8d331682217 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:20:38 +0200 Subject: [PATCH 013/247] New helper method filenames() --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 32 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index fe7f8307d3..5d2ed0c917 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -90,6 +90,10 @@ class ctkDICOMDatabasePrivate /// void createBackupFileList(); + /// + /// get all Filename values from table + QStringList filenames(QString table); + /// Name of the database file (i.e. for SQLITE the sqlite file) QString DatabaseFileName; QString LastError; @@ -325,6 +329,21 @@ bool ctkDICOMDatabasePrivate::executeScript(const QString script) { return true; } +//------------------------------------------------------------------------------ +QStringList ctkDICOMDatabasePrivate::filenames(QString table) +{ + /// get all filenames from the database + QSqlQuery allFilesQuery(this->Database); + QStringList allFileNames; + loggedExec(allFilesQuery,QString("SELECT Filename from %1 ;").arg(table) ); + + while (allFilesQuery.next()) + { + allFileNames << allFilesQuery.value(0).toString(); + } + return allFileNames; +} + //------------------------------------------------------------------------------ bool ctkDICOMDatabase::initializeDatabase(const char* sqlFileName) { @@ -422,18 +441,7 @@ QString ctkDICOMDatabase::fileForInstance(QString sopInstanceUID) QStringList ctkDICOMDatabase::allFiles() { Q_D(ctkDICOMDatabase); - - /// get all filenames from the database - QSqlQuery allFilesQuery(d->Database); - QStringList allFileNames; - allFilesQuery.prepare("SELECT Filename from Images;"); - allFilesQuery.exec(); - - while (allFilesQuery.next()) - { - allFileNames << allFilesQuery.value(0).toString(); - } - return allFileNames; + return d->filenames("Images"); } //------------------------------------------------------------------------------ From b986c835501765f8efdc94e14fa51dc3ed6fb7a3 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:21:03 +0200 Subject: [PATCH 014/247] Small documentation fix --- Libs/DICOM/Core/ctkDICOMDatabase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index e28f9f4743..31a88b91eb 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -107,7 +107,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject /// close the database. It must not be used afterwards. Q_INVOKABLE void closeDatabase(); /// - /// delete all data and reinitialize the database. + /// delete all data and (re-)initialize the database. Q_INVOKABLE bool initializeDatabase(const char* schemaFile = ":/dicom/dicom-schema.sql"); /// From cbd4657d07629ee178f3b4e0856232ac486685c2 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:21:27 +0200 Subject: [PATCH 015/247] New method to update schema and re-insert data --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 23 +++++++++++++++++++++++ Libs/DICOM/Core/ctkDICOMDatabase.h | 5 ++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 5d2ed0c917..2e67dc8457 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -351,6 +351,29 @@ bool ctkDICOMDatabase::initializeDatabase(const char* sqlFileName) return d->executeScript(sqlFileName); } +//------------------------------------------------------------------------------ +bool ctkDICOMDatabase::updateSchema(const char* schemaFile) +{ + // backup filelist + // reinit with the new schema + // reinsert everything + + Q_D(ctkDICOMDatabase); + d->createBackupFileList(); + + this->initializeDatabase(schemaFile); + + QStringList allFiles = d->filenames("Filenames_backup"); + foreach(QString file, allFiles) + { + // TODO: use QFuture + this->insert(file,false,false,true); + } + return true; + +} + + //------------------------------------------------------------------------------ void ctkDICOMDatabase::closeDatabase() { diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h index 31a88b91eb..cc228009ca 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.h +++ b/Libs/DICOM/Core/ctkDICOMDatabase.h @@ -110,6 +110,9 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject /// delete all data and (re-)initialize the database. Q_INVOKABLE bool initializeDatabase(const char* schemaFile = ":/dicom/dicom-schema.sql"); + /// updates the database schema and reinserts all existing files + Q_INVOKABLE bool updateSchema(const char* schemaFile = ":/dicom/dicom-schema.sql"); + /// /// \brief database accessors Q_INVOKABLE QStringList patients (); @@ -148,7 +151,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject Q_INVOKABLE void insert( const ctkDICOMDataset& ctkDataset, bool storeFile, bool generateThumbnail); void insert ( DcmDataset *dataset, bool storeFile = true, bool generateThumbnail = true); Q_INVOKABLE void insert ( const QString& filePath, bool storeFile = true, bool generateThumbnail = true, bool createHierarchy = true, const QString& destinationDirectoryName = QString() ); - + /// Check if file is already in database and up-to-date bool fileExistsAndUpToDate(const QString& filePath); From ef894dfc3fbd8827fcaadeae24bab775262e1e94 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:22:06 +0200 Subject: [PATCH 016/247] Extended test for updateSchema() --- .../Testing/Cpp/ctkDICOMDatabaseTest2.cpp | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp index ab75c6d3f2..a48a2da9c8 100644 --- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp +++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp @@ -67,11 +67,11 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) { std::cerr << "ctkDICOMDatabase::openDatabase() failed: " << "database should not be in memory" << std::endl; - return EXIT_FAILURE; + return EXIT_FAILURE; } bool res = database.initializeDatabase(); - + if (!res) { std::cerr << "ctkDICOMDatabase::initializeDatabase() failed." << std::endl; @@ -112,12 +112,32 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] ) std::cerr << "ctkDICOMDatabase: didn't get back the original file path" << std::endl; return EXIT_FAILURE; } - + QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE"); QString foundSeriesDescription = database.instanceValue(instanceUID, tag); + if (foundSeriesDescription != knownSeriesDescription) + { + std::cerr << "ctkDICOMDatabase: invalid element value returned" << std::endl; + return EXIT_FAILURE; + } + + // now update the database + database.updateSchema(); + + // and repeat the above checks + foundFile = database.fileForInstance(instanceUID); + + if (foundFile != dicomFilePath) + { + std::cerr << "ctkDICOMDatabase: didn't get back the original file path" << std::endl; + return EXIT_FAILURE; + } + + foundSeriesDescription = database.instanceValue(instanceUID, tag); + if (foundSeriesDescription != knownSeriesDescription) { std::cerr << "ctkDICOMDatabase: invalid element value returned" << std::endl; From 796f912e30bc11b2eab3a8e003a7de7d15689437 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:22:23 +0200 Subject: [PATCH 017/247] Removed unused parameter --- Libs/DICOM/Core/ctkDICOMIndexer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/DICOM/Core/ctkDICOMIndexer.cpp b/Libs/DICOM/Core/ctkDICOMIndexer.cpp index 84cea37c51..a89250b7b0 100644 --- a/Libs/DICOM/Core/ctkDICOMIndexer.cpp +++ b/Libs/DICOM/Core/ctkDICOMIndexer.cpp @@ -96,7 +96,7 @@ ctkDICOMIndexerPrivate::~ctkDICOMIndexerPrivate() } -void ctkDICOMIndexerPrivate::OnProgress(int progress) +void ctkDICOMIndexerPrivate::OnProgress(int) { Q_Q(ctkDICOMIndexer); From 469ed63c534b8ae8cec76a88b0c03180ad65b076 Mon Sep 17 00:00:00 2001 From: Marco Nolden Date: Sat, 14 Jul 2012 00:37:28 +0200 Subject: [PATCH 018/247] Also remove backup list after schema update --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 2e67dc8457..4a351b8185 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -90,6 +90,12 @@ class ctkDICOMDatabasePrivate /// void createBackupFileList(); + /// + /// remove the extra table containing the backup + /// + void removeBackupFileList(); + + /// /// get all Filename values from table QStringList filenames(QString table); @@ -196,6 +202,14 @@ void ctkDICOMDatabasePrivate::createBackupFileList() loggedExec(query, "INSERT INTO Filenames_backup SELECT Filename FROM Images;" ); } +//------------------------------------------------------------------------------ +void ctkDICOMDatabasePrivate::removeBackupFileList() +{ + QSqlQuery query(this->Database); + loggedExec(query, "DROP TABLE main.Filenames_backup; " ); +} + + //------------------------------------------------------------------------------ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& connectionName ) @@ -369,6 +383,8 @@ bool ctkDICOMDatabase::updateSchema(const char* schemaFile) // TODO: use QFuture this->insert(file,false,false,true); } + // TODO: check better that everything is ok + d->removeBackupFileList(); return true; } From 687faeff8107ea1e5ab986c280e1b7e0ab69423f Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Tue, 17 Jul 2012 09:31:17 -0400 Subject: [PATCH 019/247] Add additional debugging information to the database class Since there have been many bug reports about incorrectly imported dicom files, these statements will help us zero in on issue more efficiently during development. --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index db57993151..af7e52ddb9 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -709,6 +709,7 @@ void ctkDICOMDatabasePrivate::insertStudy(const ctkDICOMDataset& ctkDataset, int checkStudyExistsQuery.exec(); if(!checkStudyExistsQuery.next()) { + qDebug() << "Need to insert new study: " << studyInstanceUID; QString studyID(ctkDataset.GetElementAsString(DCM_StudyID) ); QString studyDate(ctkDataset.GetElementAsString(DCM_StudyDate) ); @@ -741,7 +742,10 @@ void ctkDICOMDatabasePrivate::insertStudy(const ctkDICOMDataset& ctkDataset, int { LastStudyInstanceUID = studyInstanceUID; } - + } + else + { + qDebug() << "Used existing study: " << studyInstanceUID; } } @@ -756,6 +760,8 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS loggedExec(checkSeriesExistsQuery); if(!checkSeriesExistsQuery.next()) { + qDebug() << "Need to insert new series: " << seriesInstanceUID; + QString seriesDate(ctkDataset.GetElementAsString(DCM_SeriesDate) ); QString seriesTime(ctkDataset.GetElementAsString(DCM_SeriesTime) ); QString seriesDescription(ctkDataset.GetElementAsString(DCM_SeriesDescription) ); @@ -795,6 +801,10 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS LastSeriesInstanceUID = seriesInstanceUID; } } + else + { + qDebug() << "Used existing series: " << seriesInstanceUID; + } } //------------------------------------------------------------------------------ @@ -859,12 +869,6 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q return; } - - - - - - // store the file if the database is not in memomry // TODO: if we are called from insert(file) we // have to do something else @@ -987,6 +991,10 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q emit q->databaseChanged(); } } + else + { + qDebug() << "No patient name or no patient id - not inserting!"; + } } //------------------------------------------------------------------------------ From a58b465a3d7f8051a18a0e438b0bf4f44bf536bd Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Tue, 17 Jul 2012 09:32:55 -0400 Subject: [PATCH 020/247] Fix bug where data would not appear in model after import The import would succeed, but since it happened during a "Future" concurrent execution the model was never aware of it and the gui would not update. Now, the model's reset slot is connected so it will be triggered when the indexing finishes. --- Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp index 450b59e32a..dbdc495c8c 100644 --- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp @@ -450,10 +450,10 @@ void ctkDICOMAppWidget::onImportDirectory(QString directory) connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()), progress, SLOT(close())); + connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()), + &d->DICOMModel, SLOT(reset())); d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory); - - d->DICOMModel.reset(); } } From 09f383f382d91e53ada17dc65f7a367e7bcb031a Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Tue, 17 Jul 2012 18:01:48 -0400 Subject: [PATCH 021/247] Enable tag caching Whenever a tag cache read or write request is made, ensure that the tag cache exists (create it if it does not exist). --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index af7e52ddb9..f46ad58a9e 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -1230,6 +1230,10 @@ bool ctkDICOMDatabase::initializeTagCache() QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString tag) { Q_D(ctkDICOMDatabase); + if ( !this->tagCacheExists() ) + { + this->initializeTagCache(); + } QSqlQuery selectValue( d->Database ); selectValue.prepare( "SELECT Value FROM TagCache WHERE SOPInstanceUID = :sopInstanceUID AND Tag = :tag" ); selectValue.bindValue(":sopInstanceUID",sopInstanceUID); @@ -1247,6 +1251,10 @@ QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString bool ctkDICOMDatabase::cacheTag(const QString sopInstanceUID, const QString tag, const QString value) { Q_D(ctkDICOMDatabase); + if ( !this->tagCacheExists() ) + { + this->initializeTagCache(); + } QSqlQuery insertTag( d->Database ); insertTag.prepare( "INSERT OR REPLACE INTO TagCache VALUES(:sopInstanceUID, :tag, :value)" ); insertTag.bindValue(":sopInstanceUID",sopInstanceUID); From 10f62c2103ac3bc752bcef43796fdff5dd35acbf Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Tue, 17 Jul 2012 18:45:41 -0400 Subject: [PATCH 022/247] Enable tag caching in the fileElement and instanceElement calls Previously cache was being used if available, but was not being auto-populated. --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index f46ad58a9e..9bd37a420f 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -522,7 +522,8 @@ QString ctkDICOMDatabase::instanceValue(const QString sopInstanceUID, const unsi QString filePath = this->fileForInstance(sopInstanceUID); if (filePath != "" ) { - return( this->fileValue(filePath, group, element) ); + value = this->fileValue(filePath, group, element); + return( value ); } else { @@ -574,7 +575,9 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short DcmTagKey tagKey(group, element); - return( dataset.GetAllElementValuesAsString(tagKey) ); + value = dataset.GetAllElementValuesAsString(tagKey); + this->cacheTag(sopInstanceUID, tag, value); + return( value ); } //------------------------------------------------------------------------------ From 2f2d5a9700bece50fee39a87053c2670a9e3acdc Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Wed, 18 Jul 2012 16:39:39 -0400 Subject: [PATCH 023/247] Added ctkDirectoryListView --- Libs/Widgets/CMakeLists.txt | 3 + Libs/Widgets/ctkDirectoryListView.cpp | 262 ++++++++++++++++++++++++++ Libs/Widgets/ctkDirectoryListView.h | 113 +++++++++++ 3 files changed, 378 insertions(+) create mode 100644 Libs/Widgets/ctkDirectoryListView.cpp create mode 100644 Libs/Widgets/ctkDirectoryListView.h diff --git a/Libs/Widgets/CMakeLists.txt b/Libs/Widgets/CMakeLists.txt index 7fc9b353fb..cd11345c57 100644 --- a/Libs/Widgets/CMakeLists.txt +++ b/Libs/Widgets/CMakeLists.txt @@ -63,6 +63,8 @@ set(KIT_SRCS ctkDateRangeWidget.h ctkDirectoryButton.cpp ctkDirectoryButton.h + ctkDirectoryListView.cpp + ctkDirectoryListView.h ctkDoubleRangeSlider.cpp ctkDoubleRangeSlider.h ctkDoubleSlider.cpp @@ -203,6 +205,7 @@ set(KIT_MOC_SRCS ctkCrosshairLabel.h ctkDateRangeWidget.h ctkDirectoryButton.h + ctkDirectoryListView.h ctkDoubleRangeSlider.h ctkDoubleSlider.h ctkDynamicSpacer.h diff --git a/Libs/Widgets/ctkDirectoryListView.cpp b/Libs/Widgets/ctkDirectoryListView.cpp new file mode 100644 index 0000000000..5cc4baa069 --- /dev/null +++ b/Libs/Widgets/ctkDirectoryListView.cpp @@ -0,0 +1,262 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + +=========================================================================*/ + +/*============================================================================== + + Program: 3D Slicer + + Copyright (c) Kitware Inc. + + See COPYRIGHT.txt + or http://www.slicer.org/copyright/copyright.txt for details. + + 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. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +==============================================================================*/ + +// Qt includes +#include +#include +#include +#include + +// QtGUI includes +#include "ctkDirectoryListView.h" + +// -------------------------------------------------------------------------- +// ctkDirectoryListViewPrivate + +//----------------------------------------------------------------------------- +class ctkDirectoryListViewPrivate +{ + Q_DECLARE_PUBLIC(ctkDirectoryListView); +protected: + ctkDirectoryListView* const q_ptr; + +public: + ctkDirectoryListViewPrivate(ctkDirectoryListView& object); + void init(); + + void addDirectory(const QString& path); + + enum + { + AbsolutePathRole = Qt::UserRole + 1 + }; + + QListView* ListView; + QStandardItemModel DirectoryListModel; +}; + +// -------------------------------------------------------------------------- +// ctkDirectoryListViewPrivate methods + +// -------------------------------------------------------------------------- +ctkDirectoryListViewPrivate::ctkDirectoryListViewPrivate(ctkDirectoryListView& object) + :q_ptr(&object) +{ +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListViewPrivate::init() +{ + Q_Q(ctkDirectoryListView); + + this->ListView = new QListView(); + this->ListView->setSelectionBehavior(QAbstractItemView::SelectRows); + this->ListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->ListView->setEditTriggers(QAbstractItemView::NoEditTriggers); + QHBoxLayout * layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(this->ListView); + q->setLayout(layout); + + this->ListView->setModel(&this->DirectoryListModel); +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListViewPrivate::addDirectory(const QString& path) +{ + Q_Q(ctkDirectoryListView); + QString absolutePath = QFileInfo(path).absoluteFilePath(); + if (!QFile::exists(absolutePath) || q->hasDirectory(absolutePath)) + { + return; + } + QStandardItem * item = new QStandardItem(path); + item->setData(QVariant(absolutePath), Qt::ToolTipRole); + item->setData(QVariant(absolutePath), ctkDirectoryListViewPrivate::AbsolutePathRole); + this->DirectoryListModel.appendRow(item); +} + +// -------------------------------------------------------------------------- +// ctkDirectoryListView methods + +// -------------------------------------------------------------------------- +ctkDirectoryListView::ctkDirectoryListView(QWidget* _parent) + : Superclass(_parent) + , d_ptr(new ctkDirectoryListViewPrivate(*this)) +{ + Q_D(ctkDirectoryListView); + d->init(); +} + +// -------------------------------------------------------------------------- +ctkDirectoryListView::~ctkDirectoryListView() +{ +} + +// -------------------------------------------------------------------------- +QStringList ctkDirectoryListView::directoryList(bool absolutePath)const +{ + Q_D(const ctkDirectoryListView); + QStringList directoryList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkDirectoryListViewPrivate::AbsolutePathRole; + } + for(int i = 0; i < d->DirectoryListModel.rowCount(); ++i) + { + directoryList << d->DirectoryListModel.data(d->DirectoryListModel.index(i, 0), role).toString(); + } + return directoryList; +} + +// -------------------------------------------------------------------------- +QStringList ctkDirectoryListView::selectedDirectoryList(bool absolutePath)const +{ + Q_D(const ctkDirectoryListView); + QStringList directoryList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkDirectoryListViewPrivate::AbsolutePathRole; + } + QModelIndexList selectedIndexes = d->ListView->selectionModel()->selectedRows(); + foreach(const QModelIndex& index, selectedIndexes) + { + directoryList << d->DirectoryListModel.data(index, role).toString(); + } + return directoryList; +} + +// -------------------------------------------------------------------------- +bool ctkDirectoryListView::hasDirectory(const QString& path)const +{ + Q_D(const ctkDirectoryListView); + QString absolutePath = QFileInfo(path).absoluteFilePath(); + QModelIndexList foundIndexes = d->DirectoryListModel.match( + d->DirectoryListModel.index(0, 0), ctkDirectoryListViewPrivate::AbsolutePathRole, + QVariant(absolutePath)); + Q_ASSERT(foundIndexes.size() < 2); + return (foundIndexes.size() != 0); +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::addDirectory(const QString& path) +{ + Q_D(ctkDirectoryListView); + d->addDirectory(path); + emit this->directoryListChanged(); +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::removeDirectory(const QString& path) +{ + Q_D(ctkDirectoryListView); + QList foundItems = d->DirectoryListModel.findItems(path); + Q_ASSERT(foundItems.count() < 2); + if (foundItems.count() == 1) + { + d->DirectoryListModel.removeRow(foundItems.at(0)->row()); + emit this->directoryListChanged(); + } +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::removeSelectedDirectories() +{ + Q_D(ctkDirectoryListView); + + QModelIndexList selectedIndexes = d->ListView->selectionModel()->selectedRows(); + bool selectedCount = selectedIndexes.count(); + while(selectedIndexes.count() > 0) + { + d->DirectoryListModel.removeRow(selectedIndexes.at(0).row()); + selectedIndexes = d->ListView->selectionModel()->selectedRows(); + } + if (selectedCount) + { + emit this->directoryListChanged(); + } +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::selectAllDirectories() +{ + Q_D(ctkDirectoryListView); + d->ListView->selectAll(); +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::clearDirectorySelection() +{ + Q_D(ctkDirectoryListView); + d->ListView->clearSelection(); +} + +// -------------------------------------------------------------------------- +void ctkDirectoryListView::setDirectoryList(const QStringList& paths) +{ + Q_D(ctkDirectoryListView); + + if (paths.count() == this->directoryList().count()) + { + int found = 0; + foreach(const QString& path, paths) + { + if (this->hasDirectory(path)) + { + ++found; + } + } + if (found == paths.count()) + { + return; + } + } + + d->DirectoryListModel.removeRows(0, d->DirectoryListModel.rowCount()); + + foreach(const QString& path, paths) + { + d->addDirectory(path); + } + emit this->directoryListChanged(); +} + diff --git a/Libs/Widgets/ctkDirectoryListView.h b/Libs/Widgets/ctkDirectoryListView.h new file mode 100644 index 0000000000..dfe24ec255 --- /dev/null +++ b/Libs/Widgets/ctkDirectoryListView.h @@ -0,0 +1,113 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + +=========================================================================*/ + +/*============================================================================== + + Program: 3D Slicer + + Copyright (c) Kitware Inc. + + See COPYRIGHT.txt + or http://www.slicer.org/copyright/copyright.txt for details. + + 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. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +==============================================================================*/ + +#ifndef __ctkDirectoryListView_h +#define __ctkDirectoryListView_h + +// Qt includes +#include + +// QtGUI includes +#include "ctkWidgetsExport.h" + +class ctkDirectoryListViewPrivate; + +class CTK_WIDGETS_EXPORT ctkDirectoryListView : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList NOTIFY directoryListChanged); +public: + /// Superclass typedef + typedef QWidget Superclass; + + /// Constructor + explicit ctkDirectoryListView(QWidget* parent = 0); + + /// Destructor + virtual ~ctkDirectoryListView(); + + /// Return True if the \a path has already been added + bool hasDirectory(const QString& path)const; + + QStringList directoryList(bool absolutePath = false)const; + + QStringList selectedDirectoryList(bool absolutePath = false)const; + +public slots: + + /// If \a path exists, add it to the view and emit signal directoryListChanged(). + /// \sa directoryListChanged() + void addDirectory(const QString& path); + + /// Remove all entries and set \a paths has current list. + /// The signal directoryListChanged() is emitted if the current list of directories is + /// different from the provided one. + /// \sa addDirectory(), directoryListChanged() + void setDirectoryList(const QStringList& paths); + + /// Remove \a path from the list. + /// The signal directoryListChanged() is emitted if the path was in the list. + /// \sa directoryListChanged() + void removeDirectory(const QString& path); + + /// \sa selectAllDirectories() + void removeSelectedDirectories(); + + /// Select all directories. + void selectAllDirectories(); + + /// Clear the current directory selection. + void clearDirectorySelection(); + +signals: + /// This signal is emitted when a directory is added to the view. + void directoryListChanged(); + +protected: + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkDirectoryListView); + Q_DISABLE_COPY(ctkDirectoryListView); + +}; + +#endif + From 854fac6835e3a46a19c29425e59dfd5f0235bca9 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Wed, 18 Jul 2012 16:39:52 -0400 Subject: [PATCH 024/247] Added ctkDirectoryListWidget --- Libs/Widgets/CMakeLists.txt | 6 + .../Resources/UI/ctkDirectoryListWidget.ui | 97 ++++++++++++ Libs/Widgets/ctkDirectoryListWidget.cpp | 142 ++++++++++++++++++ Libs/Widgets/ctkDirectoryListWidget.h | 69 +++++++++ Libs/Widgets/ctkDirectoryListWidget_p.h | 59 ++++++++ 5 files changed, 373 insertions(+) create mode 100644 Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui create mode 100644 Libs/Widgets/ctkDirectoryListWidget.cpp create mode 100644 Libs/Widgets/ctkDirectoryListWidget.h create mode 100644 Libs/Widgets/ctkDirectoryListWidget_p.h diff --git a/Libs/Widgets/CMakeLists.txt b/Libs/Widgets/CMakeLists.txt index cd11345c57..2ee3ffcca0 100644 --- a/Libs/Widgets/CMakeLists.txt +++ b/Libs/Widgets/CMakeLists.txt @@ -65,6 +65,9 @@ set(KIT_SRCS ctkDirectoryButton.h ctkDirectoryListView.cpp ctkDirectoryListView.h + ctkDirectoryListWidget.cpp + ctkDirectoryListWidget.h + ctkDirectoryListWidget_p.h ctkDoubleRangeSlider.cpp ctkDoubleRangeSlider.h ctkDoubleSlider.cpp @@ -206,6 +209,8 @@ set(KIT_MOC_SRCS ctkDateRangeWidget.h ctkDirectoryButton.h ctkDirectoryListView.h + ctkDirectoryListWidget.h + ctkDirectoryListWidget_p.h ctkDoubleRangeSlider.h ctkDoubleSlider.h ctkDynamicSpacer.h @@ -278,6 +283,7 @@ set(KIT_UI_FORMS Resources/UI/ctkThumbnailLabel.ui Resources/UI/ctkThumbnailListWidget.ui Resources/UI/ctkWorkflowGroupBox.ui + Resources/UI/ctkDirectoryListWidget.ui ) # Resources diff --git a/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui b/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui new file mode 100644 index 0000000000..661d0ae72a --- /dev/null +++ b/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui @@ -0,0 +1,97 @@ + + + ctkDirectoryListWidget + + + + 0 + 0 + 776 + 347 + + + + Form + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Paths + + + + + + Add + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 224 + + + + + + + + + + + + 0 + 0 + + + + + + + + + ctkDirectoryListView + QWidget +
ctkDirectoryListView.h
+ 1 +
+ + ctkExpandButton + QWidget +
ctkExpandButton.h
+ 1 +
+
+ + +
diff --git a/Libs/Widgets/ctkDirectoryListWidget.cpp b/Libs/Widgets/ctkDirectoryListWidget.cpp new file mode 100644 index 0000000000..74e89d862e --- /dev/null +++ b/Libs/Widgets/ctkDirectoryListWidget.cpp @@ -0,0 +1,142 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + +=========================================================================*/ + +// Qt includes +#include +#include + +// CTK includes +#include "ctkDirectoryListWidget.h" +#include "ctkDirectoryListWidget_p.h" + +//----------------------------------------------------------------------------- +// ctkDirectoryListWidgetPrivate methods + +//----------------------------------------------------------------------------- +ctkDirectoryListWidgetPrivate::~ctkDirectoryListWidgetPrivate() +{ +} + +//----------------------------------------------------------------------------- +ctkDirectoryListWidgetPrivate::ctkDirectoryListWidgetPrivate(ctkDirectoryListWidget& object) + : QObject(&object), q_ptr(&object) +{ +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::init() +{ + Q_Q(ctkDirectoryListWidget); + this->setupUi(q); +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::setupUi(QWidget * widget) +{ + this->Ui_ctkDirectoryListWidget::setupUi(widget); + + this->ExpandButton->setChecked(false); + this->ExpandButton->setMirrorOnExpand(true); + this->GroupBox->hide(); + + QObject::connect(this->AddButton, SIGNAL(clicked()), + this, SLOT(onAddClicked())); + QObject::connect(this->RemoveButton, SIGNAL(clicked()), + this, SLOT(onRemoveClicked())); + QObject::connect(this->ExpandButton, SIGNAL(clicked()), + this, SLOT(onExpandClicked())); +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::setDirectoryList(const QStringList& list) +{ + this->DirectoryList->setDirectoryList(list); +} + +//----------------------------------------------------------------------------- +QStringList ctkDirectoryListWidgetPrivate::directoryList() const +{ + return this->DirectoryList->directoryList(true); // true for absolute path. +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::onAddClicked() +{ + QString path = QFileDialog::getExistingDirectory( + this->DirectoryList, tr("Select folder"), + QString("")); + // An empty directory means that the user cancelled the dialog. + if (path.isEmpty()) + { + return; + } + this->DirectoryList->addDirectory(path); +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::onRemoveClicked() +{ + this->DirectoryList->removeSelectedDirectories(); +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::onExpandClicked() +{ + if (this->GroupBox->isVisible()) + { + this->GroupBox->hide(); + } + else + { + this->GroupBox->show(); + } +} + +//----------------------------------------------------------------------------- +// ctkDirectoryListWidget methods + +//----------------------------------------------------------------------------- +ctkDirectoryListWidget::~ctkDirectoryListWidget() +{ +} + +//----------------------------------------------------------------------------- +ctkDirectoryListWidget::ctkDirectoryListWidget(QWidget* newParent) + : Superclass(newParent) + , d_ptr(new ctkDirectoryListWidgetPrivate(*this)) +{ + Q_D(ctkDirectoryListWidget); + d->init(); +} + +//----------------------------------------------------------------------------- +void ctkDirectoryListWidget::setDirectoryList(const QStringList& list) +{ + Q_D(ctkDirectoryListWidget); + d->setDirectoryList(list); +} + +//----------------------------------------------------------------------------- +QStringList ctkDirectoryListWidget::directoryList() const +{ + Q_D(const ctkDirectoryListWidget); + return d->directoryList(); +} + diff --git a/Libs/Widgets/ctkDirectoryListWidget.h b/Libs/Widgets/ctkDirectoryListWidget.h new file mode 100644 index 0000000000..735839658e --- /dev/null +++ b/Libs/Widgets/ctkDirectoryListWidget.h @@ -0,0 +1,69 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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 __ctkDirectoryListWidget_h +#define __ctkDirectoryListWidget_h + +// Qt includes +#include +#include + +// QtGUI includes +#include "ctkWidgetsExport.h" + +class ctkDirectoryListWidgetPrivate; + +/** + * \class ctkDirectoryListWidget + * \brief A widget to maintain a list of directories, with add and remove buttons, + * such as might be used in a settings panel to select a series of directories to search. + * + * \author m.clarkson@ucl.ac.uk + */ +class CTK_WIDGETS_EXPORT ctkDirectoryListWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList) + +public: + /// Superclass typedef + typedef QWidget Superclass; + ctkDirectoryListWidget(QWidget* parent = 0); + virtual ~ctkDirectoryListWidget(); + + /// Set the directory list, which will overwrite any existing list. + void setDirectoryList(const QStringList& list); + QStringList directoryList() const; + +public Q_SLOTS: + +Q_SIGNALS: + /// directoryListChanged emmitted whenever the list of directories is changed. + void directoryListChanged(const QStringList& directories); + +protected: + QScopedPointer d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkDirectoryListWidget); + Q_DISABLE_COPY(ctkDirectoryListWidget); +}; + +#endif diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkDirectoryListWidget_p.h new file mode 100644 index 0000000000..3da4a2705c --- /dev/null +++ b/Libs/Widgets/ctkDirectoryListWidget_p.h @@ -0,0 +1,59 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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 __ctkDirectoryListWidget_p_h +#define __ctkDirectoryListWidget_p_h + +// Qt includes +#include +#include + +// CTK includes +#include "ctkDirectoryListWidget.h" +#include "ui_ctkDirectoryListWidget.h" + +//----------------------------------------------------------------------------- +/// \ingroup Widgets + +class ctkDirectoryListWidgetPrivate : public QObject, public Ui_ctkDirectoryListWidget +{ + Q_OBJECT + Q_DECLARE_PUBLIC(ctkDirectoryListWidget); +protected: + ctkDirectoryListWidget* const q_ptr; +public: + explicit ctkDirectoryListWidgetPrivate(ctkDirectoryListWidget& object); + virtual ~ctkDirectoryListWidgetPrivate(); + + void init(); + void setupUi(QWidget * parent); + + void setDirectoryList(const QStringList& list); + QStringList directoryList() const; + +public Q_SLOTS: + void onAddClicked(); + void onRemoveClicked(); + void onExpandClicked(); + +public: +}; + +#endif From 0542cc63de0546362f8b228ba723adf9fc6caf0f Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Thu, 12 Jul 2012 10:40:39 +0100 Subject: [PATCH 025/247] Connect directoryListChanged signal --- Libs/Widgets/ctkDirectoryListWidget.cpp | 11 +++++++++++ Libs/Widgets/ctkDirectoryListWidget_p.h | 1 + 2 files changed, 12 insertions(+) diff --git a/Libs/Widgets/ctkDirectoryListWidget.cpp b/Libs/Widgets/ctkDirectoryListWidget.cpp index 74e89d862e..520bfbf3cf 100644 --- a/Libs/Widgets/ctkDirectoryListWidget.cpp +++ b/Libs/Widgets/ctkDirectoryListWidget.cpp @@ -18,6 +18,8 @@ =========================================================================*/ +#include + // Qt includes #include #include @@ -62,6 +64,8 @@ void ctkDirectoryListWidgetPrivate::setupUi(QWidget * widget) this, SLOT(onRemoveClicked())); QObject::connect(this->ExpandButton, SIGNAL(clicked()), this, SLOT(onExpandClicked())); + QObject::connect(this->DirectoryList, SIGNAL(directoryListChanged()), + this, SLOT(onDirectoryListChanged())); } //----------------------------------------------------------------------------- @@ -109,6 +113,13 @@ void ctkDirectoryListWidgetPrivate::onExpandClicked() } } +//----------------------------------------------------------------------------- +void ctkDirectoryListWidgetPrivate::onDirectoryListChanged() +{ + Q_Q(ctkDirectoryListWidget); + emit (q->directoryListChanged(this->DirectoryList->directoryList())); +} + //----------------------------------------------------------------------------- // ctkDirectoryListWidget methods diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkDirectoryListWidget_p.h index 3da4a2705c..783038f760 100644 --- a/Libs/Widgets/ctkDirectoryListWidget_p.h +++ b/Libs/Widgets/ctkDirectoryListWidget_p.h @@ -52,6 +52,7 @@ public Q_SLOTS: void onAddClicked(); void onRemoveClicked(); void onExpandClicked(); + void onDirectoryListChanged(); public: }; From 0ba80449b276560c51cc29b908b6aa94fec6548c Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sat, 14 Jul 2012 22:41:46 +0100 Subject: [PATCH 026/247] Updated copyright info in ctkDirectoryListView and ctkDirectoryListWidget --- Libs/Widgets/ctkDirectoryListView.cpp | 19 +------------------ Libs/Widgets/ctkDirectoryListView.h | 19 +------------------ Libs/Widgets/ctkDirectoryListWidget.cpp | 2 +- Libs/Widgets/ctkDirectoryListWidget.h | 2 +- Libs/Widgets/ctkDirectoryListWidget_p.h | 2 +- 5 files changed, 5 insertions(+), 39 deletions(-) diff --git a/Libs/Widgets/ctkDirectoryListView.cpp b/Libs/Widgets/ctkDirectoryListView.cpp index 5cc4baa069..0a091f1804 100644 --- a/Libs/Widgets/ctkDirectoryListView.cpp +++ b/Libs/Widgets/ctkDirectoryListView.cpp @@ -16,27 +16,10 @@ See the License for the specific language governing permissions and limitations under the License. -=========================================================================*/ - -/*============================================================================== - - Program: 3D Slicer - - Copyright (c) Kitware Inc. - - See COPYRIGHT.txt - or http://www.slicer.org/copyright/copyright.txt for details. - - 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. - This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 -==============================================================================*/ +=========================================================================*/ // Qt includes #include diff --git a/Libs/Widgets/ctkDirectoryListView.h b/Libs/Widgets/ctkDirectoryListView.h index dfe24ec255..97f8b8d88d 100644 --- a/Libs/Widgets/ctkDirectoryListView.h +++ b/Libs/Widgets/ctkDirectoryListView.h @@ -16,27 +16,10 @@ See the License for the specific language governing permissions and limitations under the License. -=========================================================================*/ - -/*============================================================================== - - Program: 3D Slicer - - Copyright (c) Kitware Inc. - - See COPYRIGHT.txt - or http://www.slicer.org/copyright/copyright.txt for details. - - 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. - This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. and was partially funded by NIH grant 3P41RR013218-12S1 -==============================================================================*/ +=========================================================================*/ #ifndef __ctkDirectoryListView_h #define __ctkDirectoryListView_h diff --git a/Libs/Widgets/ctkDirectoryListWidget.cpp b/Libs/Widgets/ctkDirectoryListWidget.cpp index 520bfbf3cf..ee464f7e21 100644 --- a/Libs/Widgets/ctkDirectoryListWidget.cpp +++ b/Libs/Widgets/ctkDirectoryListWidget.cpp @@ -2,7 +2,7 @@ Library: CTK - Copyright (c) Kitware Inc. + Copyright (c) University College London. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Libs/Widgets/ctkDirectoryListWidget.h b/Libs/Widgets/ctkDirectoryListWidget.h index 735839658e..d7cb992844 100644 --- a/Libs/Widgets/ctkDirectoryListWidget.h +++ b/Libs/Widgets/ctkDirectoryListWidget.h @@ -2,7 +2,7 @@ Library: CTK - Copyright (c) Kitware Inc. + Copyright (c) University College London. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkDirectoryListWidget_p.h index 783038f760..6c258391da 100644 --- a/Libs/Widgets/ctkDirectoryListWidget_p.h +++ b/Libs/Widgets/ctkDirectoryListWidget_p.h @@ -2,7 +2,7 @@ Library: CTK - Copyright (c) Kitware Inc. + Copyright (c) University College London. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From eb53a30cb8d892b5cdd6c9721052a2dae2a59183 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sun, 15 Jul 2012 11:58:54 +0100 Subject: [PATCH 027/247] Changed ctkDirectoryListWidgetPrivate::onExpandClicked to take bool, and toggle visibility of group box --- Libs/Widgets/ctkDirectoryListWidget.cpp | 15 ++++----------- Libs/Widgets/ctkDirectoryListWidget_p.h | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Libs/Widgets/ctkDirectoryListWidget.cpp b/Libs/Widgets/ctkDirectoryListWidget.cpp index ee464f7e21..76b6ae8ba8 100644 --- a/Libs/Widgets/ctkDirectoryListWidget.cpp +++ b/Libs/Widgets/ctkDirectoryListWidget.cpp @@ -62,8 +62,8 @@ void ctkDirectoryListWidgetPrivate::setupUi(QWidget * widget) this, SLOT(onAddClicked())); QObject::connect(this->RemoveButton, SIGNAL(clicked()), this, SLOT(onRemoveClicked())); - QObject::connect(this->ExpandButton, SIGNAL(clicked()), - this, SLOT(onExpandClicked())); + QObject::connect(this->ExpandButton, SIGNAL(clicked(bool)), + this, SLOT(onExpandClicked(bool))); QObject::connect(this->DirectoryList, SIGNAL(directoryListChanged()), this, SLOT(onDirectoryListChanged())); } @@ -101,16 +101,9 @@ void ctkDirectoryListWidgetPrivate::onRemoveClicked() } //----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::onExpandClicked() +void ctkDirectoryListWidgetPrivate::onExpandClicked(bool state) { - if (this->GroupBox->isVisible()) - { - this->GroupBox->hide(); - } - else - { - this->GroupBox->show(); - } + this->GroupBox->setVisible(state); } //----------------------------------------------------------------------------- diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkDirectoryListWidget_p.h index 6c258391da..09a54188cf 100644 --- a/Libs/Widgets/ctkDirectoryListWidget_p.h +++ b/Libs/Widgets/ctkDirectoryListWidget_p.h @@ -51,7 +51,7 @@ class ctkDirectoryListWidgetPrivate : public QObject, public Ui_ctkDirectoryList public Q_SLOTS: void onAddClicked(); void onRemoveClicked(); - void onExpandClicked(); + void onExpandClicked(bool); void onDirectoryListChanged(); public: From 111acd7d8d0e0680110a546faa9cd855f6e24a5e Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sun, 15 Jul 2012 11:59:31 +0100 Subject: [PATCH 028/247] Changed size of vertical spacer in ctkDirectoryListWidget group box to get better layout when expand/un-expand --- Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui b/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui index 661d0ae72a..47272f9dae 100644 --- a/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui +++ b/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui @@ -6,8 +6,8 @@ 0 0 - 776 - 347 + 435 + 294 @@ -17,7 +17,7 @@ - + 0 0 @@ -58,7 +58,7 @@ 20 - 224 + 40 From 0cbd451858cedbb405cd34148b68285aa9484312 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Wed, 18 Jul 2012 18:13:59 -0400 Subject: [PATCH 029/247] Update PythonQt tag to fix error when building Debug against Python release Closes #203 --- CMakeExternals/PythonQt.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeExternals/PythonQt.cmake b/CMakeExternals/PythonQt.cmake index 373e8230c5..d5fa33b9db 100644 --- a/CMakeExternals/PythonQt.cmake +++ b/CMakeExternals/PythonQt.cmake @@ -53,7 +53,7 @@ if(${add_project}) message(FATAL_ERROR "error: Python is required to build ${PROJECT_NAME}") endif() - set(revision_tag 47738f9c8c5d3ffa77c8f2e1844f899e5b548f0c) + set(revision_tag 6366f002a93aa238c55f58de949d09c552cda5a9) if(${proj}_REVISION_TAG) set(revision_tag ${${proj}_REVISION_TAG}) endif() From bca72adf2f7f3a328ea7e09817ba4bb36c8a7eb0 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 13 Jul 2012 22:49:31 +0200 Subject: [PATCH 030/247] Use "CmdLineModule" naming convention in test modules. --- .../CLIModules/Blur2dImage/CMakeLists.txt | 2 - .../Core/Testing/CLIModules/CMakeLists.txt | 24 ---- .../Testing/CLIModules/Tour/CMakeLists.txt | 2 - .../CLIModules/ctkCLIModuleBlur2dImage.xml | 115 ------------------ .../Core/Testing/CMakeLists.txt | 2 +- .../Modules/Blur2dImage/CMakeLists.txt | 2 + .../ctkCmdLineModuleBlur2dImage.cpp} | 10 +- .../ctkCmdLineModuleBlur2dImage.qrc} | 2 +- .../ctkCmdLineModuleBlur2dImage.xml} | 0 .../Core/Testing/Modules/CMakeLists.txt | 24 ++++ .../Core/Testing/Modules/Tour/CMakeLists.txt | 2 + .../Tour/ctkCmdLineModuleTour.cpp} | 4 +- .../Tour/ctkCmdLineModuleTour.qrc} | 2 +- .../Tour/ctkCmdLineModuleTour.xml} | 0 14 files changed, 38 insertions(+), 153 deletions(-) delete mode 100644 Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/CMakeLists.txt delete mode 100644 Libs/CommandLineModules/Core/Testing/CLIModules/CMakeLists.txt delete mode 100644 Libs/CommandLineModules/Core/Testing/CLIModules/Tour/CMakeLists.txt delete mode 100644 Libs/CommandLineModules/Core/Testing/CLIModules/ctkCLIModuleBlur2dImage.xml create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt rename Libs/CommandLineModules/Core/Testing/{CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.cpp => Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp} (87%) rename Libs/CommandLineModules/Core/Testing/{CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.qrc => Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc} (51%) rename Libs/CommandLineModules/Core/Testing/{CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.xml => Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml} (100%) create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt rename Libs/CommandLineModules/Core/Testing/{CLIModules/Tour/ctkCLIModuleTour.cpp => Modules/Tour/ctkCmdLineModuleTour.cpp} (94%) rename Libs/CommandLineModules/Core/Testing/{CLIModules/Tour/ctkCLIModuleTour.qrc => Modules/Tour/ctkCmdLineModuleTour.qrc} (55%) rename Libs/CommandLineModules/Core/Testing/{CLIModules/Tour/ctkCLIModuleTour.xml => Modules/Tour/ctkCmdLineModuleTour.xml} (100%) diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/CMakeLists.txt deleted file mode 100644 index 347cc43562..0000000000 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ - -ctkFunctionCreateCLIModule(Blur2dImage) diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CLIModules/CMakeLists.txt deleted file mode 100644 index c077057342..0000000000 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ - -# This is very simple and for test purposes -# only. Relies on naming conventions and has -# no extensive error checking yet. -function(ctkFunctionCreateCLIModule name) - set(_src_files ${ARGN}) - list(APPEND _src_files ctkCLIModule${name}.cpp) - qt4_add_resources(_src_files ctkCLIModule${name}.qrc) - - add_executable(ctkCLIModule${name} ${_src_files}) - target_link_libraries(ctkCLIModule${name} CTKCore ${QT_LIBRARIES}) - add_dependencies(ctkCLITestModules ctkCLIModule${name}) -endfunction() - -set(_cli_modules - Blur2dImage - Tour -) - -add_custom_target(ctkCLITestModules) - -foreach(_cli_module ${_cli_modules}) - add_subdirectory(${_cli_module}) -endforeach() diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/CMakeLists.txt deleted file mode 100644 index 06b4625734..0000000000 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ - -ctkFunctionCreateCLIModule(Tour) diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/ctkCLIModuleBlur2dImage.xml b/Libs/CommandLineModules/Core/Testing/CLIModules/ctkCLIModuleBlur2dImage.xml deleted file mode 100644 index cdcae048f0..0000000000 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/ctkCLIModuleBlur2dImage.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - Tours - Execution Model Tour - - Shows one of each type of parameter. - - 1.0 - - - Daniel Blezek - - - - - Variations on scalar parameters - - - integerVariable - i - integer - - An integer without constraints - - - 30 - - - booleanParam - b - - A boolean without constraints - - - - - fileVar - 3 - Some file - - bla - input - - - dirVar - 6 - Some dir - - /home - output - - - geomVar - 3 - Some geom - - - - doubleVariable - d - double - An double with constraints - - 30 - - 0 - 1.e3 - 0 - - - - - - - Variations on vector parameters - - floatVector - f - A vector of floats - - 1.3,2,-14 - - - stringVector - string_vector - A vector of strings - - "foo",bar,"foobar" - - - - - - Variations on enumeration parameters - - stringChoice - e - enumeration - An enumeration of strings - - foo - foo - "foobar" - foofoo - - - pointVar - p - asf - - 0.5,-34.2,43 - - - - diff --git a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt index 5747ec817c..c8253c57c5 100644 --- a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(CLIModules) +add_subdirectory(Modules) #add_subdirectory(Cpp) diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt new file mode 100644 index 0000000000..4d125c250f --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt @@ -0,0 +1,2 @@ + +ctkFunctionCreateCmdLineModule(Blur2dImage) diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.cpp b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp similarity index 87% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.cpp rename to Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp index 422f0d73e6..90b9181c53 100644 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.cpp +++ b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -32,7 +33,7 @@ int main(int argc, char* argv[]) QCoreApplication app(argc, argv); // This is used by QSettings QCoreApplication::setOrganizationName("CommonTK"); - QCoreApplication::setApplicationName("CLIModuleBlur2dImage"); + QCoreApplication::setApplicationName("CmdLineModuleBlur2dImage"); ctkCommandLineParser parser; // Use Unix-style argument names @@ -50,8 +51,7 @@ int main(int argc, char* argv[]) QHash parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok); if (!ok) { - err << "Error parsing arguments: " - << parser.errorString() << "\n"; + err << "Error parsing arguments: " << parser.errorString() << "\n"; return EXIT_FAILURE; } @@ -64,7 +64,7 @@ int main(int argc, char* argv[]) if (parsedArgs.contains("xml")) { - QFile xmlDescription(":/ctkCLIModuleBlur2dImage.xml"); + QFile xmlDescription(":/ctkCmdLineModuleBlur2dImage.xml"); xmlDescription.open(QIODevice::ReadOnly); out << xmlDescription.readAll(); return EXIT_SUCCESS; @@ -72,7 +72,7 @@ int main(int argc, char* argv[]) // Do something - //out << "Got parameter: " << QCoreApplication::arguments(); + qDebug() << "Got parameter: " << QCoreApplication::arguments(); return EXIT_SUCCESS; } diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.qrc b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc similarity index 51% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.qrc rename to Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc index bf4101fec4..7cb13800ae 100644 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.qrc +++ b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc @@ -1,5 +1,5 @@ - ctkCLIModuleBlur2dImage.xml + ctkCmdLineModuleBlur2dImage.xml diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.xml b/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml similarity index 100% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Blur2dImage/ctkCLIModuleBlur2dImage.xml rename to Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml diff --git a/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt new file mode 100644 index 0000000000..4e8ed18466 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt @@ -0,0 +1,24 @@ + +# This is very simple and for test purposes +# only. Relies on naming conventions and has +# no extensive error checking yet. +function(ctkFunctionCreateCmdLineModule name) + set(_src_files ${ARGN}) + list(APPEND _src_files ctkCmdLineModule${name}.cpp) + qt4_add_resources(_src_files ctkCmdLineModule${name}.qrc) + + add_executable(ctkCmdLineModule${name} ${_src_files}) + target_link_libraries(ctkCmdLineModule${name} CTKCore ${QT_LIBRARIES}) + add_dependencies(ctkCmdLineTestModules ctkCmdLineModule${name}) +endfunction() + +set(_cmdline_modules + Blur2dImage + Tour +) + +add_custom_target(ctkCmdLineTestModules) + +foreach(_cmdline_module ${_cmdline_modules}) + add_subdirectory(${_cmdline_module}) +endforeach() diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt new file mode 100644 index 0000000000..018fe81f07 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt @@ -0,0 +1,2 @@ + +ctkFunctionCreateCmdLineModule(Tour) diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.cpp b/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp similarity index 94% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.cpp rename to Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp index c739b2be96..3f48c418ea 100644 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.cpp +++ b/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp @@ -32,7 +32,7 @@ int main(int argc, char* argv[]) QCoreApplication app(argc, argv); // This is used by QSettings QCoreApplication::setOrganizationName("CommonTK"); - QCoreApplication::setApplicationName("CLIModuleTour"); + QCoreApplication::setApplicationName("CmdLineModuleTour"); ctkCommandLineParser parser; // Use Unix-style argument names @@ -61,7 +61,7 @@ int main(int argc, char* argv[]) if (parsedArgs.contains("xml")) { - QFile xmlDescription(":/ctkCLIModuleTour.xml"); + QFile xmlDescription(":/ctkCmdLineModuleTour.xml"); xmlDescription.open(QIODevice::ReadOnly); QTextStream(stdout, QIODevice::WriteOnly) << xmlDescription.readAll(); } diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.qrc b/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc similarity index 55% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.qrc rename to Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc index 1cee651910..8c10521d47 100644 --- a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.qrc +++ b/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc @@ -1,5 +1,5 @@ - ctkCLIModuleTour.xml + ctkCmdLineModuleTour.xml diff --git a/Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.xml b/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.xml similarity index 100% rename from Libs/CommandLineModules/Core/Testing/CLIModules/Tour/ctkCLIModuleTour.xml rename to Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.xml From ba055de2ef420d5a768a8ee6b2ffcbbaa79fbcc8 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Thu, 19 Jul 2012 13:30:21 +0200 Subject: [PATCH 031/247] Support for running cmd line modules. Partial support for QFuture. --- .../ctkCLModuleExplorerMainWindow.cpp | 21 +-- Libs/CommandLineModules/Core/CMakeLists.txt | 8 +- .../Core/Testing/CMakeLists.txt | 2 +- .../Core/Testing/Cpp/CMakeLists.txt | 19 ++- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 113 +++++++++++++++ .../Cpp/ctkCmdLineModuleSignalTester.cpp | 89 ++++++++++++ .../Cpp/ctkCmdLineModuleSignalTester.h | 52 +++++++ .../Testing/Cpp/ctkModuleDescriptionTest.cpp | 92 ------------ .../Core/Testing/Modules/CMakeLists.txt | 1 + .../Testing/Modules/TestBed/CMakeLists.txt | 2 + .../TestBed/ctkCmdLineModuleTestBed.cpp | 131 ++++++++++++++++++ .../TestBed/ctkCmdLineModuleTestBed.qrc | 5 + .../TestBed/ctkCmdLineModuleTestBed.xml | 58 ++++++++ .../Core/ctkCmdLineModuleFuture.cpp | 97 ------------- .../Core/ctkCmdLineModuleFuture.h | 93 ------------- .../Core/ctkCmdLineModuleInstance.cpp | 18 +-- .../Core/ctkCmdLineModuleInstance.h | 6 +- .../Core/ctkCmdLineModuleProcess.cpp | 67 --------- .../Core/ctkCmdLineModuleProcessTask.cpp | 94 +++++++++++++ ...cess_p.h => ctkCmdLineModuleProcessTask.h} | 31 +++-- .../Core/ctkCmdLineModuleRunException.cpp | 61 ++++++++ .../Core/ctkCmdLineModuleRunException.h | 46 ++++++ 22 files changed, 709 insertions(+), 397 deletions(-) create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h delete mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc create mode 100644 Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp rename Libs/CommandLineModules/Core/{ctkCmdLineModuleProcess_p.h => ctkCmdLineModuleProcessTask.h} (63%) create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp index a067df4571..e62a309e39 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp @@ -26,8 +26,9 @@ #include #include #include -//#include +#include +#include #include ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : @@ -66,8 +67,6 @@ void ctkCLModuleExplorerMainWindow::addModule(const QString &location) void ctkCLModuleExplorerMainWindow::on_actionRun_triggered() { - qDebug() << "Creating module command line..."; - ctkCmdLineModuleInstance* moduleInstance = mapTabToModuleRef[ui->mainTabWidget->currentIndex()]; if (!moduleInstance) { @@ -78,14 +77,16 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered() QStringList cmdLineArgs = moduleInstance->commandLineArguments(); qDebug() << cmdLineArgs; + QFuture future = moduleInstance->run(); + try + { + future.waitForFinished(); + } + catch (const ctkException& e) + { + qDebug() << e.printStackTrace(); + } - //ctkCmdLineModuleProcessFuture future = moduleInstance->run(); - //future.waitForFinished(); - //qDebug() << future.standardOutput(); - -// connect(&futureWatcher, SIGNAL(finished()), this, SLOT(futureFinished())); -// ctkCmdLineModuleProcessFuture future = moduleManager.run(moduleRef); -// futureWatcher.setFuture(future); } void ctkCLModuleExplorerMainWindow::futureFinished() diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 8ca38a2f6c..0ee3414a15 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -16,8 +16,6 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT") set(KIT_SRCS ctkCmdLineModuleDescription.cpp ctkCmdLineModuleDescriptionPrivate.h - ctkCmdLineModuleFuture.h - #ctkCmdLineModuleFuture.cpp ctkCmdLineModuleInstance.cpp ctkCmdLineModuleInstanceFactory.cpp ctkCmdLineModuleManager.cpp @@ -26,10 +24,10 @@ set(KIT_SRCS ctkCmdLineModuleParameterGroup.cpp ctkCmdLineModuleParameterGroupPrivate.h ctkCmdLineModuleParameterParsers_p.h - #ctkCmdLineModuleProcess.cpp - ctkCmdLineModuleProcess_p.h + ctkCmdLineModuleProcessTask.cpp ctkCmdLineModuleReference.cpp ctkCmdLineModuleReferencePrivate.cpp + ctkCmdLineModuleRunException.cpp ctkCmdLineModuleXmlException.cpp ctkCmdLineModuleXmlMsgHandler_p.h ctkCmdLineModuleXmlMsgHandler.cpp @@ -42,7 +40,7 @@ set(KIT_SRCS # Headers that should run through moc set(KIT_MOC_SRCS ctkCmdLineModuleInstance.h - #ctkCmdLineModuleProcess_p.h + ctkCmdLineModuleProcessTask.h ) # UI files diff --git a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt index c8253c57c5..0f709b9555 100644 --- a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt @@ -1,2 +1,2 @@ add_subdirectory(Modules) -#add_subdirectory(Cpp) +add_subdirectory(Cpp) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 1dccd77c0b..07e9102269 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -1,20 +1,29 @@ set(KIT ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp - ctkModuleDescriptionTest.cpp + ctkCmdLineModuleFutureTest.cpp ) -SET (TestsToRun ${Tests}) -REMOVE (TestsToRun ${KIT}CppTests.cpp) +set(TestsToRun ${Tests}) +remove(TestsToRun ${KIT}CppTests.cpp) + +set(SRC_FILES ${Tests} + ctkCmdLineModuleSignalTester.cpp +) + +qt4_wrap_cpp(SRC_FILES ctkCmdLineModuleSignalTester.h) set(LIBRARY_NAME ${PROJECT_NAME}) -add_executable(${KIT}CppTests ${Tests}) +add_executable(${KIT}CppTests ${SRC_FILES}) target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) +add_dependencies(${KIT}CppTests ctkCmdLineTestModules) # # Add Tests # -SIMPLE_TEST( ctkModuleDescriptionTest.cpp ) +foreach(_test ${TestsToRun}) + SIMPLE_TEST(${_test}) +endforeach() diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp new file mode 100644 index 0000000000..51f3b1a554 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -0,0 +1,113 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ctkCmdLineModuleSignalTester.h" + +#include +#include +#include +#include +#include + +#include + + +class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleInstanceFactory +{ +public: + + virtual ctkCmdLineModuleInstance* create(const ctkCmdLineModuleReference& moduleRef) + { + struct ModuleTestInstance : public ctkCmdLineModuleInstance + { + ModuleTestInstance(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleInstance(moduleRef) {} + + virtual QObject* guiHandle() const { return NULL; } + + virtual QVariant value(const QString& parameter) const + { + return this->moduleReference().description().parameter(parameter).defaultValue(); + } + + virtual void setValue(const QString& /*parameter*/, const QVariant& /*value*/) + { + // do nothing + } + }; + + return new ModuleTestInstance(moduleRef); + } +}; + + +int ctkCmdLineModuleFutureTest(int argc, char* argv[]) +{ + QCoreApplication app(argc, argv); + + ctkCmdLineModuleTestInstanceFactory factory; + ctkCmdLineModuleManager manager(&factory); + + QString moduleFilename = app.applicationDirPath() + "/ctkCmdLineModuleTestBed"; + ctkCmdLineModuleReference moduleRef = manager.registerModule(moduleFilename); + if (!moduleRef) + { + qCritical() << "Module at" << moduleFilename << "could not be registered"; + } + + ctkCmdLineModuleInstance* moduleInstance = manager.createModuleInstance(moduleRef); + + QList expectedSignals; + expectedSignals.push_back("module.started"); + expectedSignals.push_back("module.finished"); + + ctkCmdLineModuleSignalTester signalTester; + + QFutureWatcher watcher; + QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); + QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); + + QFuture future = moduleInstance->run(); + watcher.setFuture(future); + + future.waitForFinished(); + + // process pending events + QCoreApplication::processEvents(); + + delete moduleInstance; + + if (!signalTester.checkSignals(expectedSignals)) + { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp new file mode 100644 index 0000000000..ead66cd575 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp @@ -0,0 +1,89 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleSignalTester.h" + +#include + +void ctkCmdLineModuleSignalTester::moduleStarted() +{ + events.push_back("module.started"); +} + +void ctkCmdLineModuleSignalTester::moduleFinished() +{ + events.push_back("module.finished"); +} + +void ctkCmdLineModuleSignalTester::filterStarted(const QString &name, const QString &comment) +{ + qDebug() << "Filter started:" << name << "(" << comment << ")"; + events.push_back("filter.started"); +} + +void ctkCmdLineModuleSignalTester::filterProgress(float progress) +{ + qDebug() << "progress:" << progress; + events.push_back("filter.progress"); +} + +void ctkCmdLineModuleSignalTester::filterFinished(const QString &name) +{ + qDebug() << "Filter finished:" << name; + events.push_back("filter.finished"); +} + +bool ctkCmdLineModuleSignalTester::checkSignals(const QList& expectedSignals) +{ + if (events.size() != expectedSignals.size()) + { + dumpSignals(expectedSignals); + return false; + } + + for (int i=0; i < expectedSignals.size(); ++i) + { + if (expectedSignals[i] != events[i]) + { + dumpSignals(expectedSignals); + return false; + } + } + return true; +} + +void ctkCmdLineModuleSignalTester::dumpSignals(const QList& expectedSignals) +{ + int max = events.size() > expectedSignals.size() ? events.size() : expectedSignals.size(); + qDebug() << "Expected signal -- Actual signal"; + for (int i = 0; i < max; ++i) + { + QString sig = i < events.size() ? events[i] : QString(); + if (i < expectedSignals.size()) + { + qDebug() << " " << expectedSignals[i] << "--" << sig; + } + else + { + qDebug() << " " << "- NONE - " << "--" << sig; + } + } +} diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h new file mode 100644 index 0000000000..44d1cdb24b --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h @@ -0,0 +1,52 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULESIGNALTESTER_H +#define CTKCMDLINEMODULESIGNALTESTER_H + +#include +#include + +class ctkCmdLineModuleSignalTester : public QObject +{ + Q_OBJECT + +public: + + bool checkSignals(const QList& expectedSignals); + void dumpSignals(const QList& expectedSignals); + + +public Q_SLOTS: + + void moduleStarted(); + void moduleFinished(); + + void filterStarted(const QString& name, const QString& comment); + void filterProgress(float progress); + void filterFinished(const QString& name); + +private: + + QList events; +}; + +#endif // CTKCMDLINEMODULESIGNALTESTER_H diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp deleted file mode 100644 index e3fd174cbd..0000000000 --- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkModuleDescriptionTest.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/*========================================================================= - - Library: CTK - - Copyright (c) 2010 Kitware Inc. - - 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. - -=========================================================================*/ - -// Qt includes -#include - -// CTK includes -#include "ctkModuleDescription.h" -#include - -//----------------------------------------------------------------------------- -int ctkModuleDescriptionTest(int argc, char * argv [] ) -{ - Q_UNUSED(argc); - Q_UNUSED(argv); - - - ctkModuleParameter param; - param[ "Tag" ] = "MyTag"; - param[ "Name" ] = "MyName"; - param[ "Description" ] = "MyDescription"; - param[ "Label" ] = "MyLabel"; - param[ "CPPType" ] = "MyCPPType"; - param[ "Type" ] = "MyType"; - param[ "Reference" ] = "MyReference"; - param[ "Hidden" ] = "false"; - param[ "ArgType" ] = "MyArgType"; - param[ "StringToType" ] = "MyStringToType"; - param[ "Default" ] = "MyDefault"; - param[ "Flag" ] = "MyFlag"; - param[ "LongFlag" ] = "MyLongFlag"; - param[ "Constraints" ] = "MyConstraints"; - param[ "Minimum" ] = "MyMinimum"; - param[ "Maximum" ] = "MyMaximum"; - param[ "Channel" ] = "MyChannel"; - param[ "Index" ] = "MyIndex"; - param[ "Multiple" ] = "false"; - param[ "Aggregate" ] = "false"; - param[ "FileExtensions" ] = ".vtk,.jpg"; - param[ "FlagAliases" ] = "MyFlagAliases"; - param[ "DeprecatedFlagAliases" ] = "MyDeprecatedFlagAliases"; - param[ "LongFlagAliases" ] = "MyLongFlagAliases"; - param[ "DeprecatedLongFlagAliases" ] = "MyDeprecatedLongFlagAliases"; - param[ "CoordinateSystem" ] = "MyCoordinateSystem"; - - - ctkModuleParameterGroup group; - group[ "Label" ] = "MyLabel"; - group[ "Description" ] = "MyDescription"; - group[ "Advanced" ] = "MyAdvanced"; - - - ctkModuleDescription module; - module[ "Category" ] = "MyCategory"; - module[ "Index" ] = "MyIndex"; - module[ "Title" ] = "MyTitle"; - module[ "Description" ] = "MyDescription"; - module[ "DocumentationURL" ] = "MyDocumentationURL"; - module[ "License" ] = "MyLicense"; - module[ "Acknowledgements" ] = "MyAcknowledgements"; - module[ "Contributor" ] = "MyContributor"; - module[ "Type" ] = "MyType"; - module[ "AlternativeType" ] = "MyAlternativeType"; - module[ "Target" ] = "MyTarget"; - module[ "AlternativeTarget" ] = "MyAlternativeTarget"; - module[ "Location" ] = "MyLocation"; - - group.addParameter( new ctkModuleParameter(param) ); - module.addParameterGroup( new ctkModuleParameterGroup(group) ); - - QTextStream stream(stdout); - stream<< module; - - return EXIT_SUCCESS; -} diff --git a/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt index 4e8ed18466..3167cc6493 100644 --- a/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt @@ -14,6 +14,7 @@ endfunction() set(_cmdline_modules Blur2dImage + TestBed Tour ) diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt new file mode 100644 index 0000000000..1d619eaa59 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt @@ -0,0 +1,2 @@ + +ctkFunctionCreateCmdLineModule(TestBed) diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp new file mode 100644 index 0000000000..67ba86d41a --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp @@ -0,0 +1,131 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char* argv[]) +{ + QCoreApplication app(argc, argv); + // This is used by QSettings + QCoreApplication::setOrganizationName("CommonTK"); + QCoreApplication::setApplicationName("CmdLineModuleTestBed"); + + ctkCommandLineParser parser; + // Use Unix-style argument names + parser.setArgumentPrefix("--", "-"); + + // Add command line argument names + parser.addArgument("help", "h", QVariant::Bool, "Show this help text"); + parser.addArgument("xml", "", QVariant::Bool, "Print a XML description of this modules command line interface"); + parser.addArgument("runtime", "", QVariant::Int, "Runtime in seconds", 1); + parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0); + parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0); + parser.addArgument("errorText", "", QVariant::String, "Error text (will not be printed on exit code 0)"); + QTextStream out(stdout, QIODevice::WriteOnly); + QTextStream err(stderr, QIODevice::WriteOnly); + + // Parse the command line arguments + bool ok = false; + QHash parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok); + if (!ok) + { + err << "Error parsing arguments: " << parser.errorString() << "\n"; + return EXIT_FAILURE; + } + + // Show a help message + if (parsedArgs.contains("help") || parsedArgs.contains("h")) + { + out << parser.helpText(); + out.setFieldWidth(parser.fieldWidth()); + out.setFieldAlignment(QTextStream::AlignLeft); + out << " ..."; + out << "One or more output strings\n"; + return EXIT_SUCCESS; + } + + if (parsedArgs.contains("xml")) + { + QFile xmlDescription(":/ctkCmdLineModuleTestBed.xml"); + xmlDescription.open(QIODevice::ReadOnly); + out << xmlDescription.readAll(); + return EXIT_SUCCESS; + } + + // Do something + + float runtime = parsedArgs["runtime"].toFloat(); + float exitTime = parsedArgs["exitTime"].toFloat(); + int exitTimeMillis = static_cast(exitTime/2.0 * 1000.0); + int exitCode = parsedArgs["exitCode"].toInt(); + QString errorText = parsedArgs["errorText"].toString(); + + QStringList outputs = parser.unparsedArguments(); + + if (outputs.empty()) + { + // no outputs given, just return + if (exitCode != 0) + { + err << errorText; + } + return exitCode; + } + + float stepTime = runtime / static_cast(outputs.size()); + + QTime time; + time.start(); + + struct timespec nanostep; + + foreach(QString output, outputs) + { + if (exitTimeMillis != 0 && exitTimeMillis < time.elapsed()) + { + if (exitCode != 0) + { + err << errorText; + } + return exitCode; + } + + // simulate some work + nanostep.tv_sec = static_cast(stepTime); + double millisecs = (stepTime - static_cast(stepTime)) * 1000.0; + nanostep.tv_nsec = static_cast(millisecs * 1000.0 * 1000.0); + nanosleep(&nanostep, NULL); + + // print the first output + out << output; endl(out); + } + + return EXIT_SUCCESS; +} diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc new file mode 100644 index 0000000000..2203813d6b --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc @@ -0,0 +1,5 @@ + + + ctkCmdLineModuleTestBed.xml + + diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml new file mode 100644 index 0000000000..e1739cfdfe --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml @@ -0,0 +1,58 @@ + + + Testing + Test Bed + +Configurable behaviour for testing purposes. + + 1.0 + + + Sascha Zelzer + + + + Configures the runtime behaviour of this module. + + runtimeVar + runtime + An integer without constraints + + 1 + + 0 + 60 + 1 + + + + fileVar + 0 + Output files which will be reported as the progress text via a QFutureWatcher. + + output + + + exitTimeVar + exitTime + The exit time of the module (premature finish). + + 0 + + + exitCodeVar + exitCode + The exit code of the module. + + 0 + + + errorTextVar + errorText + Final error message (not displayed if the exit code is 0). + + + + + + diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp deleted file mode 100644 index 67a472e11d..0000000000 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics - - 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 - - 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. - -=============================================================================*/ - -#include "ctkCmdLineModuleFuture.h" - -struct ctkCmdLineModuleFutureInterfacePrivate -{ - ctkCmdLineModuleFutureInterfacePrivate() - : refCount(1), _exitCode(0), _exitStatus(QProcess::NormalExit), - _processError(QProcess::UnknownError) - {} - - QAtomicInt refCount; - - int _exitCode; - QProcess::ExitStatus _exitStatus; - QProcess::ProcessError _processError; - QString _errorString; - QString _stdOut; - QString _stdErr; -}; - -ctkCmdLineModuleFutureInterface::QFutureInterface(State initialState) - : QFutureInterfaceBase(initialState), d(new ctkCmdLineModuleFutureInterfacePrivate) -{ } - -ctkCmdLineModuleFutureInterface::QFutureInterface(const ctkCmdLineModuleFutureInterface& other) - : QFutureInterfaceBase(other), d(other.d) -{ - d->refCount.ref(); -} - -ctkCmdLineModuleFutureInterface ctkCmdLineModuleFutureInterface::canceledResult() -{ return ctkCmdLineModuleFutureInterface(State(Started | Finished | Canceled)); } - -ctkCmdLineModuleFutureInterface& ctkCmdLineModuleFutureInterface::operator=(const ctkCmdLineModuleFutureInterface& other) -{ - QFutureInterfaceBase::operator=(other); - other.d->refCount.ref(); - if(!d->refCount.deref()) delete d; - d = other.d; - return *this; -} - -int ctkCmdLineModuleFutureInterface::exitCode() const -{ QMutexLocker lock(this->mutex()); return d->_exitCode; } - -void ctkCmdLineModuleFutureInterface::reportExitCode(int code) -{ QMutexLocker lock(this->mutex()); d->_exitCode = code; } - -QProcess::ExitStatus ctkCmdLineModuleFutureInterface::exitStatus() const -{ QMutexLocker lock(this->mutex()); return d->_exitStatus; } - -void ctkCmdLineModuleFutureInterface::reportExitStatus(QProcess::ExitStatus status) -{ QMutexLocker lock(this->mutex()); d->_exitStatus = status; } - -QProcess::ProcessError ctkCmdLineModuleFutureInterface::error() const -{ QMutexLocker lock(this->mutex()); return d->_processError; } - -void ctkCmdLineModuleFutureInterface::reportProcessError(QProcess::ProcessError procErr) -{ QMutexLocker lock(this->mutex()); d->_processError = procErr; } - -QString ctkCmdLineModuleFutureInterface::errorString() const -{ QMutexLocker lock(this->mutex()); return d->_errorString; } - -void ctkCmdLineModuleFutureInterface::reportErrorString(const QString& errorStr) -{ QMutexLocker lock(this->mutex()); d->_errorString = errorStr; } - -QString ctkCmdLineModuleFutureInterface::standardOutput() const -{ QMutexLocker lock(this->mutex()); return d->_stdOut; } - -void ctkCmdLineModuleFutureInterface::reportStandardOutput(const QString& stdOut) -{ QMutexLocker lock(this->mutex()); d->_stdOut = stdOut; } - -QString ctkCmdLineModuleFutureInterface::standardError() const -{ QMutexLocker lock(this->mutex()); return d->_stdErr; } - -void ctkCmdLineModuleFutureInterface::reportStandardError(const QString& stdErr) -{ QMutexLocker lock(this->mutex()); d->_stdErr = stdErr; } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h deleted file mode 100644 index 342691c728..0000000000 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h +++ /dev/null @@ -1,93 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics - - 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 - - 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 CTKCMDLINEMODULEFUTURE_H -#define CTKCMDLINEMODULEFUTURE_H - -#include - -//#include -//#include -#include - -/** - * \ingroup CommandLineModulesCore - */ -class ctkCmdLineModuleFuture -{ - -public: - - ctkCmdLineModuleFuture() - : d(ctkCmdLineModuleFutureInterface::canceledResult()) - { } - - explicit ctkCmdLineModuleFuture(const ctkCmdLineModuleProcess& p) // internal - : d(*p) - { } - - ctkCmdLineModuleFuture(const ctkCmdLineModuleFuture &other) - : d(other.d) - { } - - ~ctkCmdLineModuleFuture() - { } - - ctkCmdLineModuleFuture& operator=(const ctkCmdLineModuleFuture& other); - bool operator==(const ctkCmdLineModuleFuture& other) const { return (d == other.d); } - bool operator!=(const ctkCmdLineModuleFuture& other) const { return (d != other.d); } - - void cancel() { d.cancel(); } - bool isCanceled() const { return d.isCanceled(); } - - bool isStarted() const { return d.isStarted(); } - bool isFinished() const { return d.isFinished(); } - bool isRunning() const { return d.isRunning(); } - - int exitCode() const { return d.exitCode(); } - int exitStatus() const { return d.exitStatus(); } - QProcess::ProcessError error() const { return d.error(); } - QString errorString() const { return d.errorString(); } - - QString standardOutput() const { return d.standardOutput(); } - QString standardError() const { return d.standardError(); } - - int progressValue() const { return d.progressValue(); } - int progressMinimum() const { return d.progressMinimum(); } - int progressMaximum() const { return d.progressMaximum(); } - QString progressText() const { return d.progressText(); } - void waitForFinished() { d.waitForFinished(); } - -private: - - friend class ctkCmdLineModuleFutureWatcher; - - mutable ctkCmdLineModuleProcess d; -}; - - -inline ctkCmdLineModuleFuture& ctkCmdLineModuleFuture::operator=(const ctkCmdLineModuleFuture& other) -{ - d = other.d; - return *this; -} - -#endif // CTKCMDLINEMODULEFUTURE_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp index a2fa7b5831..fc184302aa 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp @@ -24,12 +24,13 @@ #include "ctkCmdLineModuleParameter.h" #include "ctkCmdLineModuleParameterGroup.h" #include "ctkCmdLineModuleReference.h" -#include "ctkCmdLineModuleProcess_p.h" +#include "ctkCmdLineModuleProcessTask.h" #include "ctkException.h" #include #include +#include struct ctkCmdLineModuleInstancePrivate @@ -146,16 +147,15 @@ QStringList ctkCmdLineModuleInstance::commandLineArguments() const return cmdLineArgs; } -struct ctkCmdLineModuleFuture {}; - -ctkCmdLineModuleFuture ctkCmdLineModuleInstance::run() const +QFuture ctkCmdLineModuleInstance::run() const { -// // TODO: manage memory QStringList args = commandLineArguments(); - qDebug() << args; -// ctkCmdLineModuleProcessRunner* moduleProcess = -// new ctkCmdLineModuleProcessRunner(d->ModuleReference.location(), args); -// return moduleProcess->start(); + + // Instances of ctkCmdLineModuleProcessTask are auto-deleted by the + // thread pool. + ctkCmdLineModuleProcessTask* moduleProcess = + new ctkCmdLineModuleProcessTask(d->ModuleReference.location(), args); + return moduleProcess->start(); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h index b0b4ab2082..bd5a898854 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h @@ -27,8 +27,8 @@ #include template class QHash; +template class QFuture; -class ctkCmdLineModuleFuture; class ctkCmdLineModuleReference; class ctkCmdLineModuleInstancePrivate; @@ -59,7 +59,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleInstance : public QObject QStringList commandLineArguments() const; - ctkCmdLineModuleFuture run() const; + QFuture run() const; Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value); @@ -67,8 +67,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleInstance : public QObject ctkCmdLineModuleInstance(const ctkCmdLineModuleReference& moduleRef); - //virtual QObject* parameterValueModel() const; - private: friend class ctkCmdLineModuleInstancePrivate; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp deleted file mode 100644 index bca2161175..0000000000 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcess.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics - - 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 - - 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. - -=============================================================================*/ - -#include "ctkCmdLineModuleProcess_p.h" - - -ctkCmdLineModuleProcess::ctkCmdLineModuleProcess(const QString& location, const QStringList& args) - : process(), location(location), args(args) -{ -} - -ctkCmdLineModuleFuture ctkCmdLineModuleProcess::start() -{ - this->reportStarted(); - ctkCmdLineModuleFuture future(this); - connect(&process, SIGNAL(started()), this, SLOT(processStarted())); - connect(&process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError))); - connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus))); - - process.start(location, args); - return future; -} - -void ctkCmdLineModuleProcess::processStarted() -{ - qDebug() << "Reporting process started"; - this->reportStarted(); -} - -void ctkCmdLineModuleProcess::processFinished(int exitCode, QProcess::ExitStatus status) -{ - Q_UNUSED(exitCode) - Q_UNUSED(status) - qDebug() << "Reporting process finished"; - this->reportExitCode(exitCode); - this->reportExitStatus(status); - this->reportProcessError(process.error()); - this->reportErrorString(process.errorString()); - this->reportStandardOutput(process.readAllStandardOutput()); - this->reportStandardError(process.readAllStandardError()); - this->reportFinished(); -} - -void ctkCmdLineModuleProcess::processError(QProcess::ProcessError) -{ - //qDebug() << "Reporting process error"; - //this->reportException(ctkCmdLineModuleProcessException(process.errorString(), process.exitCode(), - // process.exitStatus())); -} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp new file mode 100644 index 0000000000..6dfc8fd5ef --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp @@ -0,0 +1,94 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleProcessTask.h" +#include "ctkCmdLineModuleRunException.h" + +#include +#include +#include +#include +#include + + +ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args) + : location(location), args(args) +{ +} + +ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask() +{ +} + +QFuture ctkCmdLineModuleProcessTask::start() +{ + this->setRunnable(this); + this->reportStarted(); + QFuture future = this->future(); + QThreadPool::globalInstance()->start(this, /*m_priority*/ 0); + return future; +} + +void ctkCmdLineModuleProcessTask::run() +{ + if (this->isCanceled()) + { + this->reportFinished(); + return; + } + + QProcess process; + QEventLoop localLoop; + connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit())); + connect(&process, SIGNAL(error(QProcess::ProcessError)), SLOT(error(QProcess::ProcessError))); + connect(&process, SIGNAL(readyReadStandardError()), SLOT(readyReadStandardError())); + connect(&process, SIGNAL(readyReadStandardOutput()), SLOT(readyReadStandardOutput())); + + process.start(location, args); + + localLoop.exec(); + + if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit) + { + QString msg = "The process running \"%1\" "; + msg += process.exitStatus() == QProcess::CrashExit ? QString("crashed: ") + : QString("exited with code %1: ").arg(process.exitCode()); + msg += process.readAllStandardError(); + this->reportException(ctkCmdLineModuleRunException(msg)); + } + + this->setProgressValueAndText(100, process.readAllStandardOutput()); + + //this->reportResult(result); + this->reportFinished(); +} + +void ctkCmdLineModuleProcessTask::error(QProcess::ProcessError error) +{ +} + +void ctkCmdLineModuleProcessTask::readyReadStandardError() +{ +} + +void ctkCmdLineModuleProcessTask::readyReadStandardOutput() +{ +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcess_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h similarity index 63% rename from Libs/CommandLineModules/Core/ctkCmdLineModuleProcess_p.h rename to Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h index 1c56510d6e..94466d436a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcess_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h @@ -19,37 +19,40 @@ =============================================================================*/ -#ifndef CTKCMDLINEMODULEPROCESS_P_H -#define CTKCMDLINEMODULEPROCESS_P_H +#ifndef CTKCMDLINEMODULEPROCESSTASK_H +#define CTKCMDLINEMODULEPROCESSTASK_H + +#include #include +#include +#include #include -class ctkCmdLineModuleFuture; - -class ctkCmdLineModuleProcess : public QObject +class ctkCmdLineModuleProcessTask : public QObject, public QFutureInterface, public QRunnable { Q_OBJECT public: - ctkCmdLineModuleProcess(const QString& location, const QStringList& args); + ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args); + ~ctkCmdLineModuleProcessTask(); - ctkCmdLineModuleFuture start(); + QFuture start(); -protected Q_SLOTS: + void run(); - void processStarted(); - - void processFinished(int exitCode, QProcess::ExitStatus status); +protected Q_SLOTS: - void processError(QProcess::ProcessError); + void error(QProcess::ProcessError error); + void readyReadStandardError(); + void readyReadStandardOutput(); private: - QProcess process; const QString location; const QStringList args; + QString result; }; -#endif // CTKCMDLINEMODULEPROCESSRUNNER_P_H +#endif // CTKCMDLINEMODULEPROCESSTASK_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp new file mode 100644 index 0000000000..125c7b67e1 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +BlueBerry Platform + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "ctkCmdLineModuleRunException.h" + +ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg) + : QtConcurrent::Exception(), ctkException(msg) +{ +} + +ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause) + : QtConcurrent::Exception(), ctkException(msg, cause) +{ +} + +ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o) + : QtConcurrent::Exception(o), ctkException(o) +{ +} + +ctkCmdLineModuleRunException::~ctkCmdLineModuleRunException() throw() +{ +} + +const char* ctkCmdLineModuleRunException::name() const throw() +{ + return "CTK CommandLineModule Run Exception"; +} + +const char* ctkCmdLineModuleRunException::className() const throw() +{ + return "ctkCmdLineModuleRunException"; +} + +ctkCmdLineModuleRunException* ctkCmdLineModuleRunException::clone() const +{ + return new ctkCmdLineModuleRunException(*this); +} + +void ctkCmdLineModuleRunException::rethrow() const +{ + throw *this; +} + +void ctkCmdLineModuleRunException::raise() const +{ + throw *this; +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h new file mode 100644 index 0000000000..b15490853e --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h @@ -0,0 +1,46 @@ +/*=================================================================== + +BlueBerry Platform + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef CTKCMDLINEMODULERUNEXCEPTION_H +#define CTKCMDLINEMODULERUNEXCEPTION_H + +#include + +#include + +class ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkException +{ +public: + + explicit ctkCmdLineModuleRunException(const QString& msg); + + ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause); + ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o); + + ctkCmdLineModuleRunException& operator=(const ctkCmdLineModuleRunException& o); + + ~ctkCmdLineModuleRunException() throw(); + + virtual const char* name() const throw(); + virtual const char* className() const throw(); + virtual ctkCmdLineModuleRunException* clone() const; + virtual void rethrow() const; + + virtual void raise() const; + +}; + +#endif // CTKCMDLINEMODULERUNEXCEPTION_H From e4fd9a56d8928e5fd15475b1a0efc0dc4e788c5c Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Thu, 19 Jul 2012 13:30:38 +0200 Subject: [PATCH 032/247] Do not take ownership of the module instance factory. --- Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 8f8d34ae13..c22ed48cf7 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -50,7 +50,6 @@ ctkCmdLineModuleManager::ctkCmdLineModuleManager(ctkCmdLineModuleInstanceFactory ctkCmdLineModuleManager::~ctkCmdLineModuleManager() { - delete d->InstanceFactory; } ctkCmdLineModuleReference From b21cab6fb25ca63a9b5475446e37fface7a3768a Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Thu, 19 Jul 2012 13:31:02 +0200 Subject: [PATCH 033/247] Create a QLineEdit for "string" parameter types. --- .../Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl index c383999da9..46af17b638 100644 --- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -283,11 +283,11 @@ - + From 48a295827affdaf3a72a52300415783a48aa1004 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Thu, 19 Jul 2012 13:31:56 +0200 Subject: [PATCH 034/247] First implementation of XML progress report parsing and watching. --- Libs/CommandLineModules/Core/CMakeLists.txt | 5 + .../Core/Testing/Cpp/CMakeLists.txt | 1 + ...ctkCmdLineModuleXmlProgressWatcherTest.cpp | 62 +++++++ .../ctkCmdLineModuleXmlProgressWatcher.cpp | 165 ++++++++++++++++++ .../Core/ctkCmdLineModuleXmlProgressWatcher.h | 53 ++++++ 5 files changed, 286 insertions(+) create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 0ee3414a15..a387b7fe5d 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -25,6 +25,7 @@ set(KIT_SRCS ctkCmdLineModuleParameterGroupPrivate.h ctkCmdLineModuleParameterParsers_p.h ctkCmdLineModuleProcessTask.cpp + ctkCmdLineModuleXmlProgressWatcher.cpp ctkCmdLineModuleReference.cpp ctkCmdLineModuleReferencePrivate.cpp ctkCmdLineModuleRunException.cpp @@ -43,6 +44,10 @@ set(KIT_MOC_SRCS ctkCmdLineModuleProcessTask.h ) +qt4_wrap_cpp(_dummy ctkCmdLineModuleXmlProgressWatcher.h) +set_source_files_properties(ctkCmdLineModuleXmlProgressWatcher.cpp + PROPERTIES OBJECT_DEPENDS ${_dummy}) + # UI files set(KIT_UI_FORMS ) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 07e9102269..8d484978ba 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -2,6 +2,7 @@ set(KIT ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp ctkCmdLineModuleFutureTest.cpp + ctkCmdLineModuleXmlProgressWatcherTest.cpp ) set(TestsToRun ${Tests}) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp new file mode 100644 index 0000000000..42bf71915e --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp @@ -0,0 +1,62 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + + +#include + +#include "ctkCmdLineModuleSignalTester.h" + +#include +#include +#include + +#include + + +int ctkCmdLineModuleXmlProgressWatcherTest(int argc, char* argv[]) +{ + QCoreApplication app(argc, argv); + + QByteArray input; + QBuffer buffer(&input); + buffer.open(QIODevice::ReadWrite); + + QByteArray ba = "My Filter" + "Awesome filter" + "0.3" + "0.6" + "0.9" + "My Filter23"; + + ctkCmdLineModuleXmlProgressWatcher progressWatcher(&buffer); + + ctkCmdLineModuleSignalTester signalTester; + signalTester.connect(&progressWatcher, SIGNAL(filterStarted(QString,QString)), &signalTester, SLOT(filterStarted(QString,QString))); + signalTester.connect(&progressWatcher, SIGNAL(filterProgress(float)), &signalTester, SLOT(filterProgress(float))); + signalTester.connect(&progressWatcher, SIGNAL(filterFinished(QString)), &signalTester, SLOT(filterFinished(QString))); + + QDataStream xmlOut(&buffer); + xmlOut << ba; + + QCoreApplication::processEvents(); + + return EXIT_SUCCESS; +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp new file mode 100644 index 0000000000..d59693738e --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -0,0 +1,165 @@ +/*=================================================================== + +BlueBerry Platform + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "ctkCmdLineModuleXmlProgressWatcher.h" + +#include +#include + +#include + +namespace { + +static QString FILTER_START = "filter-start"; +static QString FILTER_NAME = "filter-name"; +static QString FILTER_COMMENT = "filter-comment"; +static QString FILTER_PROGRESS = "filter-progress"; +static QString FILTER_END = "filter-end"; + +} + +class ctkCmdLineModuleXmlProgressWatcherPrivate +{ +public: + + ctkCmdLineModuleXmlProgressWatcherPrivate(QIODevice* input, ctkCmdLineModuleXmlProgressWatcher* qq) + : input(input), q(qq), error(false) + {} + + void _q_readyRead() + { + QByteArray ba = input->readAll(); + qDebug() << input->pos() << " [" << input->bytesAvailable() << "]:" << ba; + //reader.addData(ba); + //parseProgressXml(); + } + + void parseProgressXml() + { + QXmlStreamReader::TokenType type = reader.readNext(); + while(type != QXmlStreamReader::Invalid) + { + switch(type) + { + case QXmlStreamReader::NoToken: break; + case QXmlStreamReader::StartElement: + { + QStringRef name = reader.name(); + if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0) + { + stack.push_back(FILTER_START); + currentName.clear(); + currentComment.clear(); + } + else if (name.compare(FILTER_NAME, Qt::CaseInsensitive) == 0) + { + if (stack.back() == FILTER_START || stack.back() == FILTER_END) + { + currentName = reader.name().toString().trimmed(); + } + } + else if (name.compare(FILTER_COMMENT, Qt::CaseInsensitive) == 0) + { + if (stack.back() == FILTER_START) + { + currentComment = reader.name().toString().trimmed(); + } + } + else if (name.compare(FILTER_PROGRESS, Qt::CaseInsensitive) == 0) + { + if (!stack.empty()) + { + if (!error) + { + emit q->filterXmlError(QString("\"%1\" must be a top-level element, found at line %2.") + .arg(FILTER_PROGRESS).arg(reader.lineNumber())); + } + continue; + } + emit q->filterProgress(reader.text().toString().toFloat()); + } + type = reader.readNext(); + break; + } + case QXmlStreamReader::EndElement: + { + QStringRef name = reader.name(); + if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0) + { + if (stack.back() != FILTER_START) + { + if (!error) + { + emit q->filterXmlError(QString("Unexpected end tag \"%1\" found at line %2.") + .arg(FILTER_END).arg(reader.lineNumber())); + } + continue; + } + stack.pop_back(); + emit q->filterStarted(currentName, currentComment); + } + else if (name.compare(FILTER_END, Qt::CaseInsensitive) == 0) + { + if (!stack.empty()) + { + if (!error) + { + emit q->filterXmlError(QString("\"%1\" must be a top-level element, found at line %2.") + .arg(FILTER_PROGRESS).arg(reader.lineNumber())); + } + continue; + } + stack.pop_back(); + emit q->filterFinished(currentName); + } + type = reader.readNext(); + break; + } + default: + type = reader.readNext(); + } + } + } + + QIODevice* input; + ctkCmdLineModuleXmlProgressWatcher* q; + bool error; + QXmlStreamReader reader; + QList stack; + QString currentName; + QString currentComment; +}; + +ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice* input) + : d(new ctkCmdLineModuleXmlProgressWatcherPrivate(input, this)) +{ + if (d->input == NULL) return; + + if (!(d->input->openMode() & QIODevice::ReadOnly)) + { + input->open(QIODevice::ReadOnly); + } + connect(d->input, SIGNAL(readyRead()), SLOT(_q_readyRead())); + + // start parsing + d->_q_readyRead(); +} + +ctkCmdLineModuleXmlProgressWatcher::~ctkCmdLineModuleXmlProgressWatcher() +{ +} + +#include "moc_ctkCmdLineModuleXmlProgressWatcher.cxx" diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h new file mode 100644 index 0000000000..d1eb6b99d7 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h @@ -0,0 +1,53 @@ +/*=================================================================== + +BlueBerry Platform + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef CTKCMDLINEMODULEXMLPROGRESSWATCHER_H +#define CTKCMDLINEMODULEXMLPROGRESSWATCHER_H + +#include "ctkCommandLineModulesCoreExport.h" + +#include + +class ctkCmdLineModuleXmlProgressWatcherPrivate; + +class QIODevice; + +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlProgressWatcher : public QObject +{ + Q_OBJECT + +public: + + ctkCmdLineModuleXmlProgressWatcher(QIODevice* input); + ~ctkCmdLineModuleXmlProgressWatcher(); + +Q_SIGNALS: + + void filterStarted(const QString& name, const QString& comment); + void filterProgress(float progress); + void filterFinished(const QString& name); + void filterXmlError(const QString& error); + +private: + + friend class ctkCmdLineModuleXmlProgressWatcherPrivate; + + Q_PRIVATE_SLOT(d, void _q_readyRead()) + + QScopedPointer d; +}; + +#endif // CTKCMDLINEMODULEXMLPROGRESSWATCHER_H From 7c4be0fb51df33e48d939ede218b5c8fe392893f Mon Sep 17 00:00:00 2001 From: Steve Pieper Date: Thu, 19 Jul 2012 10:19:20 -0400 Subject: [PATCH 035/247] Fix for possible null DcmObject Didn't happen with older dcmtk (3.6), but appears to happen with newer versions so check for it. --- Libs/DICOM/Core/ctkDICOMDatabase.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp index 9bd37a420f..c6809d54f3 100644 --- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp +++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp @@ -468,12 +468,15 @@ void ctkDICOMDatabase::loadFileHeader (QString fileName) while (dataset->nextObject(stack, true) == EC_Normal) { DcmObject *dO = stack.top(); - QString tag = QString("%1,%2").arg( - dO->getGTag(),4,16,QLatin1Char('0')).arg( - dO->getETag(),4,16,QLatin1Char('0')); - std::ostringstream s; - dO->print(s); - d->LoadedHeader[tag] = QString(s.str().c_str()); + if (dO) + { + QString tag = QString("%1,%2").arg( + dO->getGTag(),4,16,QLatin1Char('0')).arg( + dO->getETag(),4,16,QLatin1Char('0')); + std::ostringstream s; + dO->print(s); + d->LoadedHeader[tag] = QString(s.str().c_str()); + } } } return; From a0aa45580540da16701eb16405a0a71417169e7b Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Thu, 12 Jul 2012 13:12:17 +0100 Subject: [PATCH 036/247] Added basic ctkCmdLineModulePathBuilder and ctkCmdLineModuleDefaultPathBuilder Conflicts: Libs/CommandLineModules/Core/CMakeLists.txt --- Libs/CommandLineModules/Core/CMakeLists.txt | 2 + .../ctkCmdLineModuleDefaultPathBuilder.cpp | 104 ++++++++++++++++++ .../Core/ctkCmdLineModuleDefaultPathBuilder.h | 66 +++++++++++ .../Core/ctkCmdLineModulePathBuilder.cpp | 26 +++++ .../Core/ctkCmdLineModulePathBuilder.h | 42 +++++++ 5 files changed, 240 insertions(+) create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index a387b7fe5d..a58eef1031 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -14,6 +14,7 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT") # Source files set(KIT_SRCS + ctkCmdLineModuleDefaultPathBuilder.cpp ctkCmdLineModuleDescription.cpp ctkCmdLineModuleDescriptionPrivate.h ctkCmdLineModuleInstance.cpp @@ -24,6 +25,7 @@ set(KIT_SRCS ctkCmdLineModuleParameterGroup.cpp ctkCmdLineModuleParameterGroupPrivate.h ctkCmdLineModuleParameterParsers_p.h + ctkCmdLineModulePathBuilder.cpp ctkCmdLineModuleProcessTask.cpp ctkCmdLineModuleXmlProgressWatcher.cpp ctkCmdLineModuleReference.cpp diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp new file mode 100644 index 0000000000..febc293342 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp @@ -0,0 +1,104 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleDefaultPathBuilder.h" +#include +#include +#include +#include + +struct ctkCmdLineModuleDefaultPathBuilderPrivate +{ +public: + ctkCmdLineModuleDefaultPathBuilderPrivate(); + ~ctkCmdLineModuleDefaultPathBuilderPrivate(); + QStringList build(); +}; + +//----------------------------------------------------------------------------- +// ctkCmdLineModuleDefaultPathBuilderPrivate methods + +//----------------------------------------------------------------------------- +ctkCmdLineModuleDefaultPathBuilderPrivate::ctkCmdLineModuleDefaultPathBuilderPrivate() +{ + +} + +//----------------------------------------------------------------------------- +ctkCmdLineModuleDefaultPathBuilderPrivate::~ctkCmdLineModuleDefaultPathBuilderPrivate() +{ + +} + +//----------------------------------------------------------------------------- +QStringList ctkCmdLineModuleDefaultPathBuilderPrivate::build() +{ + QStringList result; + + QString suffix = "cli-modules"; + + char *ctkModuleLoadPath = getenv("CTK_MODULE_LOAD_PATH"); + if (ctkModuleLoadPath != NULL) + { + QDir dir = QDir(QString(ctkModuleLoadPath)); + if (dir.exists()) + { + result << dir.canonicalPath(); + } + } + + if (QDir::home().exists()) + { + result << QDir::homePath(); + result << QDir::homePath() + QDir::separator() + suffix; + } + + if (QDir::current().exists()) + { + result << QDir::currentPath(); + result << QDir::currentPath() + QDir::separator() + suffix; + } + + result << QCoreApplication::applicationDirPath(); + result << QCoreApplication::applicationDirPath() + QDir::separator() + suffix; + + return result; +} + +//----------------------------------------------------------------------------- +// ctkCmdLineModuleDefaultPathBuilder methods + +//----------------------------------------------------------------------------- +ctkCmdLineModuleDefaultPathBuilder::ctkCmdLineModuleDefaultPathBuilder() + : d(new ctkCmdLineModuleDefaultPathBuilderPrivate) +{ +} + +//----------------------------------------------------------------------------- +ctkCmdLineModuleDefaultPathBuilder::~ctkCmdLineModuleDefaultPathBuilder() +{ +} + +//----------------------------------------------------------------------------- +QStringList ctkCmdLineModuleDefaultPathBuilder::build() +{ + return d->build(); +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h new file mode 100644 index 0000000000..9edb29f9f2 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h @@ -0,0 +1,66 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 __ctkCmdLineModuleDefaultPathBuilder_h +#define __ctkCmdLineModuleDefaultPathBuilder_h + +#include "ctkCommandLineModulesCoreExport.h" +#include +#include + +class ctkCmdLineModuleDefaultPathBuilderPrivate; + +/** + * \class ctkCmdLineModuleDefaultPathBuilder + * \brief Builds up a list of file paths to search for command line modules. + * + * Unfinished: + * + *
+ * Implements the following basic strategy:
+ * 1. CTK_MODULE_LOAD_PATH environment variable
+ * 2. Home directory
+ * 3. Home directory / cli-modules
+ * 4. Current working directory
+ * 5. Current working directory / cli-modules
+ * 6. Application directory
+ * 7. Application directory / cli-modules
+ * 
+ * + * \author m.clarkson@ucl.ac.uk + */ +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDefaultPathBuilder +{ + +public: + + ctkCmdLineModuleDefaultPathBuilder(); + ~ctkCmdLineModuleDefaultPathBuilder(); + + virtual QStringList build(); + +private: + + QScopedPointer d; + Q_DISABLE_COPY(ctkCmdLineModuleDefaultPathBuilder) +}; + +#endif diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp new file mode 100644 index 0000000000..4b3374862e --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp @@ -0,0 +1,26 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModulePathBuilder.h" + +ctkCmdLineModulePathBuilder::~ctkCmdLineModulePathBuilder() +{ +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h new file mode 100644 index 0000000000..7be01f404b --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h @@ -0,0 +1,42 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEPATHBUILDER_H +#define CTKCMDLINEMODULEPATHBUILDER_H + +#include + +#include "ctkCommandLineModulesCoreExport.h" + +/** + * \class ctkCmdLineModulePathBuilder + * \brief Prototype (unfinished) interface for objects that can build + * up a list of file paths, stored in a QStringList. + * \author m.clarkson@ucl.ac.uk + */ +struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModulePathBuilder +{ + virtual ~ctkCmdLineModulePathBuilder(); + + virtual QStringList build() = 0; +}; + +#endif // CTKCMDLINEMODULEPATHBUILDER_H From c8eb1d44363aaf8a4c1de9f964ff7fb3f66f6ea7 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Thu, 12 Jul 2012 13:36:41 +0100 Subject: [PATCH 037/247] Options for ctkCmdLineModuleDefaultPathBuilder to default all directories to off --- .../ctkCmdLineModuleDefaultPathBuilder.cpp | 108 +++++++++++++++--- .../Core/ctkCmdLineModuleDefaultPathBuilder.h | 16 ++- 2 files changed, 105 insertions(+), 19 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp index febc293342..3055ce98cb 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp @@ -30,7 +30,18 @@ struct ctkCmdLineModuleDefaultPathBuilderPrivate public: ctkCmdLineModuleDefaultPathBuilderPrivate(); ~ctkCmdLineModuleDefaultPathBuilderPrivate(); - QStringList build(); + QStringList build() const; + + void setLoadFromHomeDir(const bool& doLoad); + void setLoadFromCurrentDir(const bool& doLoad); + void setLoadFromApplicationDir(const bool& doLoad); + void setLoadFromCtkModuleLoadPath(const bool& doLoad); + + bool LoadFromHomeDir; + bool LoadFromCurrentDir; + bool LoadFromApplicationDir; + bool LoadFromCtkModuleLoadPath; + }; //----------------------------------------------------------------------------- @@ -38,6 +49,10 @@ struct ctkCmdLineModuleDefaultPathBuilderPrivate //----------------------------------------------------------------------------- ctkCmdLineModuleDefaultPathBuilderPrivate::ctkCmdLineModuleDefaultPathBuilderPrivate() +: LoadFromHomeDir(false) +, LoadFromCurrentDir(false) +, LoadFromApplicationDir(false) +, LoadFromCtkModuleLoadPath(false) { } @@ -49,36 +64,73 @@ ctkCmdLineModuleDefaultPathBuilderPrivate::~ctkCmdLineModuleDefaultPathBuilderPr } //----------------------------------------------------------------------------- -QStringList ctkCmdLineModuleDefaultPathBuilderPrivate::build() +void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromHomeDir(const bool& doLoad) +{ + LoadFromHomeDir = doLoad; +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCurrentDir(const bool& doLoad) +{ + LoadFromCurrentDir = doLoad; +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromApplicationDir(const bool& doLoad) +{ + LoadFromApplicationDir = doLoad; +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCtkModuleLoadPath(const bool& doLoad) +{ + LoadFromCtkModuleLoadPath = doLoad; +} + + +//----------------------------------------------------------------------------- +QStringList ctkCmdLineModuleDefaultPathBuilderPrivate::build() const { QStringList result; QString suffix = "cli-modules"; - char *ctkModuleLoadPath = getenv("CTK_MODULE_LOAD_PATH"); - if (ctkModuleLoadPath != NULL) + if (LoadFromCtkModuleLoadPath) { - QDir dir = QDir(QString(ctkModuleLoadPath)); - if (dir.exists()) + char *ctkModuleLoadPath = getenv("CTK_MODULE_LOAD_PATH"); + if (ctkModuleLoadPath != NULL) { - result << dir.canonicalPath(); + QDir dir = QDir(QString(ctkModuleLoadPath)); + if (dir.exists()) + { + result << dir.canonicalPath(); + } } } - if (QDir::home().exists()) + if (LoadFromHomeDir) { - result << QDir::homePath(); - result << QDir::homePath() + QDir::separator() + suffix; + if (QDir::home().exists()) + { + result << QDir::homePath(); + result << QDir::homePath() + QDir::separator() + suffix; + } } - if (QDir::current().exists()) + if (LoadFromCurrentDir) { - result << QDir::currentPath(); - result << QDir::currentPath() + QDir::separator() + suffix; + if (QDir::current().exists()) + { + result << QDir::currentPath(); + result << QDir::currentPath() + QDir::separator() + suffix; + } } - result << QCoreApplication::applicationDirPath(); - result << QCoreApplication::applicationDirPath() + QDir::separator() + suffix; + if (LoadFromApplicationDir) + { + result << QCoreApplication::applicationDirPath(); + result << QCoreApplication::applicationDirPath() + QDir::separator() + suffix; + } return result; } @@ -98,7 +150,31 @@ ctkCmdLineModuleDefaultPathBuilder::~ctkCmdLineModuleDefaultPathBuilder() } //----------------------------------------------------------------------------- -QStringList ctkCmdLineModuleDefaultPathBuilder::build() +QStringList ctkCmdLineModuleDefaultPathBuilder::build() const { return d->build(); } + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilder::setLoadFromHomeDir(const bool& doLoad) +{ + d->setLoadFromHomeDir(doLoad); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCurrentDir(const bool& doLoad) +{ + d->setLoadFromCurrentDir(doLoad); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilder::setLoadFromApplicationDir(const bool& doLoad) +{ + d->setLoadFromApplicationDir(doLoad); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCtkModuleLoadPath(const bool& doLoad) +{ + d->setLoadFromCtkModuleLoadPath(doLoad); +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h index 9edb29f9f2..11064933b9 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h @@ -30,12 +30,14 @@ class ctkCmdLineModuleDefaultPathBuilderPrivate; /** * \class ctkCmdLineModuleDefaultPathBuilder - * \brief Builds up a list of file paths to search for command line modules. + * \brief Builds up a list of directory paths to search for command line modules. * * Unfinished: * *
- * Implements the following basic strategy:
+ * Implements the following basic strategy, depending on which boolean flags are on:
+ * By default they are all off, as directory scanning is often time consuming.
+ *
  * 1. CTK_MODULE_LOAD_PATH environment variable
  * 2. Home directory
  * 3. Home directory / cli-modules
@@ -55,7 +57,15 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDefaultPathBuilder
   ctkCmdLineModuleDefaultPathBuilder();
   ~ctkCmdLineModuleDefaultPathBuilder();
 
-  virtual QStringList build();
+  virtual void setLoadFromHomeDir(const bool& doLoad);
+
+  virtual void setLoadFromCurrentDir(const bool& doLoad);
+
+  virtual void setLoadFromApplicationDir(const bool& doLoad);
+
+  virtual void setLoadFromCtkModuleLoadPath(const bool& doLoad);
+
+  virtual QStringList build() const;
 
 private:
 

From 359cff89332edbfd6bbbfc2c15adfd31353979f6 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Fri, 13 Jul 2012 17:36:49 +0100
Subject: [PATCH 038/247] added missing #include 

Conflicts:

	Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
---
 Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
index fc184302aa..8c8f416de4 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
@@ -31,7 +31,7 @@
 #include 
 #include 
 #include 
-
+#include 
 
 struct ctkCmdLineModuleInstancePrivate
 {

From 6248a2585e71cc54c7c653af7ac654820eae245c Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Wed, 18 Jul 2012 12:43:35 +0100
Subject: [PATCH 039/247] Implemented ctkCmdLineModuleManager::moduleReference
 and ctkCmdLineModuleManager::unregisterModule

---
 Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index c22ed48cf7..f4352cb692 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -92,14 +92,14 @@ ctkCmdLineModuleManager::registerModule(const QString& location)
   return ref;
 }
 
-void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference&)
+void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
 {
-  throw ctkException("not implemented yet");
+  d->Cache.remove(ref.location());
 }
 
 ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QString& location) const
 {
-  throw ctkException("not implemented yet");
+  return d->Cache[location];
 }
 
 QList ctkCmdLineModuleManager::moduleReferences() const

From 45d8e97bb17dc4fb4376ef38bab8a3a6514f42aa Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Wed, 18 Jul 2012 12:44:19 +0100
Subject: [PATCH 040/247] Added new class ctkCmdLineModuleDirectoryWatcher

Conflicts:

	Libs/CommandLineModules/Core/CMakeLists.txt
---
 Libs/CommandLineModules/Core/CMakeLists.txt   |   3 +
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp | 392 ++++++++++++++++++
 .../Core/ctkCmdLineModuleDirectoryWatcher.h   | 100 +++++
 .../ctkCmdLineModuleDirectoryWatcherPrivate.h | 151 +++++++
 4 files changed, 646 insertions(+)
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h

diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index a58eef1031..3e6fc4033c 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -17,6 +17,7 @@ set(KIT_SRCS
   ctkCmdLineModuleDefaultPathBuilder.cpp
   ctkCmdLineModuleDescription.cpp
   ctkCmdLineModuleDescriptionPrivate.h
+  ctkCmdLineModuleDirectoryWatcher.cpp
   ctkCmdLineModuleInstance.cpp
   ctkCmdLineModuleInstanceFactory.cpp
   ctkCmdLineModuleManager.cpp
@@ -42,6 +43,8 @@ set(KIT_SRCS
 
 # Headers that should run through moc
 set(KIT_MOC_SRCS
+  ctkCmdLineModuleDirectoryWatcher.h
+  ctkCmdLineModuleDirectoryWatcherPrivate.h
   ctkCmdLineModuleInstance.h
   ctkCmdLineModuleProcessTask.h
 )
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
new file mode 100644
index 0000000000..1e9bd3c1f5
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
@@ -0,0 +1,392 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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
+
+  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.
+
+=============================================================================*/
+
+#include "ctkCmdLineModuleDirectoryWatcher.h"
+#include "ctkCmdLineModuleDirectoryWatcherPrivate.h"
+#include "ctkCmdLineModuleManager.h"
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+//-----------------------------------------------------------------------------
+// ctkCmdLineModuleDirectoryWatcher methods
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleDirectoryWatcher::ctkCmdLineModuleDirectoryWatcher(ctkCmdLineModuleManager* moduleManager)
+  : d(new ctkCmdLineModuleDirectoryWatcherPrivate(moduleManager))
+{
+  connect(d.data(), SIGNAL(modulesChanged()), this, SLOT(onModulesChanged()));
+}
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleDirectoryWatcher::~ctkCmdLineModuleDirectoryWatcher()
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcher::setDebug(const bool& debug)
+{
+  d->setDebug(debug);
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcher::setDirectories(const QStringList& directories)
+{
+  d->setDirectories(directories);
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcher::directories()
+{
+  return d->directories();
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcher::files()
+{
+  return d->files();
+}
+
+
+//-----------------------------------------------------------------------------
+QHash ctkCmdLineModuleDirectoryWatcher::filenameToReferenceMap() const
+{
+  return d->filenameToReferenceMap();
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcher::onModulesChanged()
+{
+  emit modulesChanged();
+}
+
+//-----------------------------------------------------------------------------
+// ctkCmdLineModuleDirectoryWatcherPrivate methods
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleDirectoryWatcherPrivate::ctkCmdLineModuleDirectoryWatcherPrivate(ctkCmdLineModuleManager* moduleManager)
+: ModuleManager(moduleManager)
+, FileSystemWatcher(NULL)
+, Debug(false)
+{
+  FileSystemWatcher = new QFileSystemWatcher();
+
+  connect(this->FileSystemWatcher, SIGNAL(fileChanged(QString)), this, SLOT(onFileChanged(QString)));
+  connect(this->FileSystemWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(onDirectoryChanged(QString)));
+}
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleDirectoryWatcherPrivate::~ctkCmdLineModuleDirectoryWatcherPrivate()
+{
+  delete this->FileSystemWatcher;
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(const bool& debug)
+{
+  this->Debug = debug;
+}
+
+
+//-----------------------------------------------------------------------------
+QHash ctkCmdLineModuleDirectoryWatcherPrivate::filenameToReferenceMap() const
+{
+  return this->MapFileNameToReference;
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::directories()
+{
+  return this->FileSystemWatcher->directories();
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::files()
+{
+  return this->FileSystemWatcher->files();
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::setDirectories(const QStringList& directories)
+{
+  QStringList validDirectories = this->filterInvalidDirectories(directories);
+  this->setModuleReferences(validDirectories);
+  this->updateWatchedPaths(validDirectories, this->MapFileNameToReference.keys());
+  emit modulesChanged();
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::updateWatchedPaths(const QStringList& directories, const QStringList& files)
+{
+  QStringList currentDirectories = this->directories();
+  QStringList currentFiles = this->files();
+
+  if (currentDirectories.size() > 0)
+  {
+    this->FileSystemWatcher->removePaths(currentDirectories);
+  }
+  if (currentFiles.size() > 0)
+  {
+    this->FileSystemWatcher->removePaths(currentFiles);
+  }
+
+  if (directories.size() > 0)
+  {
+    this->FileSystemWatcher->addPaths(directories);
+  }
+  if (files.size() > 0)
+  {
+    this->FileSystemWatcher->addPaths(files);
+  }
+}
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::filterInvalidDirectories(const QStringList& directories)
+{
+  QStringList result;
+
+  QString path;
+  foreach (path, directories)
+  {
+    if (!path.isNull() && !path.isEmpty() && !path.trimmed().isEmpty())
+    {
+      QDir dir = QDir(path);
+      if (dir.exists())
+      {
+        result << dir.absolutePath();
+      }
+    }
+  }
+
+  return result;
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::extractCurrentlyWatchedFilenamesInDirectory(const QString& path)
+{
+  QStringList result;
+
+  QDir dir(path);
+  if (dir.exists())
+  {
+    QList keys = this->MapFileNameToReference.keys();
+
+    QString fileName;
+    foreach(fileName, keys)
+    {
+      QFileInfo fileInfo(fileName);
+      if (fileInfo.absolutePath() == dir.absolutePath())
+      {
+        result << fileInfo.absoluteFilePath();
+      }
+    }
+  }
+
+  return result;
+}
+
+
+//-----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::getExecutablesInDirectory(const QString& path)
+{
+  QStringList result;
+
+  QString executable;
+  QFileInfo executableFileInfo;
+
+  QDir dir = QDir(path);
+  if (dir.exists())
+  {
+    dir.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::Executable);
+    QFileInfoList executablesFileInfoList = dir.entryInfoList();
+
+    foreach (executableFileInfo, executablesFileInfoList)
+    {
+      executable = executableFileInfo.absoluteFilePath();
+      result << executable;
+    }
+  }
+
+  return result;
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringList &directories)
+{
+  // Note: This method, is called from setDirectories and updateModuleReferences,
+  // so the input directories list may be longer or shorter than the currently watched directories.
+  // In addition, within those directories, programs may have been added/removed.
+
+  QString path;
+  QStringList currentlyWatchedDirectories = this->directories();
+
+  // First remove modules from current directories that are no longer in the requested "directories" list.
+  foreach (path, currentlyWatchedDirectories)
+  {
+    if (!directories.contains(path))
+    {
+      QStringList currentlyWatchedFiles = this->extractCurrentlyWatchedFilenamesInDirectory(path);
+
+      QString filename;
+      foreach (filename, currentlyWatchedFiles)
+      {
+        this->unloadModule(filename);
+      }
+    }
+  }
+
+  // Now for each requested directory.
+  foreach (path, directories)
+  {
+    // Existing folder.
+    if (currentlyWatchedDirectories.contains(path))
+    {
+      QStringList currentlyWatchedFiles = this->extractCurrentlyWatchedFilenamesInDirectory(path);
+      QStringList executablesInDirectory = this->getExecutablesInDirectory(path);
+
+      QString executable;
+      foreach (executable, currentlyWatchedFiles)
+      {
+        if (!executablesInDirectory.contains(executable))
+        {
+          this->unloadModule(executable);
+        }
+      }
+
+      foreach(executable, executablesInDirectory)
+      {
+        if (!currentlyWatchedFiles.contains(executable))
+        {
+          this->loadModule(executable);
+        }
+      }
+    }
+    else
+    {
+      // New folder
+      QStringList executables = this->getExecutablesInDirectory(path);
+
+      QString executable;
+      foreach (executable, executables)
+      {
+        this->loadModule(executable);
+      }
+    }
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::updateModuleReferences(const QString &directory)
+{
+  // Note: If updateModuleReferences is only called from onDirectoryChanged which is only called
+  // when an EXISTING directory is updated, then this if clause should never be true.
+
+  QStringList currentlyWatchedDirectories = this->directories();
+  if (!currentlyWatchedDirectories.contains(directory))
+  {
+    currentlyWatchedDirectories << directory;
+  }
+  this->setModuleReferences(currentlyWatchedDirectories);
+}
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleReference ctkCmdLineModuleDirectoryWatcherPrivate::loadModule(const QString& pathToExecutable)
+{
+  ctkCmdLineModuleReference ref = this->ModuleManager->registerModule(pathToExecutable, !this->Debug);
+  if (ref)
+  {
+    this->MapFileNameToReference[pathToExecutable] = ref;
+  }
+  return ref;
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModule(const QString& pathToExecutable)
+{
+  ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(pathToExecutable);
+  if (ref)
+  {
+    this->ModuleManager->unregisterModule(ref);
+    this->MapFileNameToReference.remove(pathToExecutable);
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(const QString& path)
+{
+  ctkCmdLineModuleReference ref = this->loadModule(path);
+  if (ref)
+  {
+    if (this->Debug) qDebug() << "Reloaded " << path;
+    emit modulesChanged();
+  }
+  else
+  {
+    if (this->Debug) qDebug() << "ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(" << path << "): failed to load module";
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+void ctkCmdLineModuleDirectoryWatcherPrivate::onDirectoryChanged(const QString &path)
+{
+  QStringList directories;
+  directories << path;
+
+  QStringList validDirectories = this->filterInvalidDirectories(directories);
+
+  if (validDirectories.size() > 0)
+  {
+    updateModuleReferences(path);
+
+    if (this->Debug) qDebug() << "Reloaded modules in" << path;
+    emit modulesChanged();
+  }
+  else
+  {
+    if (this->Debug) qDebug() << "ctkCmdLineModuleDirectoryWatcherPrivate::onDirectoryChanged(" << path << "): failed to load modules, as path invalid.";
+  }
+}
+
+
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
new file mode 100644
index 0000000000..538f894c65
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
@@ -0,0 +1,100 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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
+
+  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 __ctkCmdLineModuleDirectoryWatcher_h
+#define __ctkCmdLineModuleDirectoryWatcher_h
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ctkCmdLineModuleReference.h"
+
+class ctkCmdLineModuleManager;
+class ctkCmdLineModuleDirectoryWatcherPrivate;
+
+/**
+ * \class ctkCmdLineModuleDirectoryWatcher
+ * \brief Provides directory scanning to load new modules into a ctkCmdLineModuleManager.
+ * \ingroup CommandLineModulesCore
+ * \author m.clarkson@ucl.ac.uk
+ *
+ * This class provides directory scanning and automatic loading of command line modules.
+ * The client should call setDirectories() to set the list of directories, and listen
+ * to the signal modulesChanged to know when to re-build the GUI representation.
+ */
+class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  ctkCmdLineModuleDirectoryWatcher(ctkCmdLineModuleManager* moduleManager);
+  virtual ~ctkCmdLineModuleDirectoryWatcher();
+
+  /**
+   * \brief Set the watcher into debug mode, for more output.
+   * \param debug if true, you get more output, otherwise, less output.
+   */
+  void setDebug(const bool& debug);
+
+  /**
+   * \brief Set the directories to be watched.
+   * \param directories a StringList of directory names. If any of these are invalid, they will be filtered out and ignored.
+   */
+  void setDirectories(const QStringList& directories);
+
+  /**
+   * \brief Returns the list of directories currently being watched.
+   */
+  QStringList directories();
+
+  /**
+   * \brief Returns the list of files (command line apps) currently being watched.
+   */
+  QStringList files();
+
+  /**
+   * \brief Retrieves a map of filenames (command line apps) and their command line module reference.
+   */
+  QHash filenameToReferenceMap() const;
+
+Q_SIGNALS:
+
+  /**
+   * \brief Signals that the modules have changed, so GUI's can re-build their menus.
+   */
+  void modulesChanged();
+
+private Q_SLOTS:
+
+  /**
+   * \brief Private slot, so we can connect to the ctkCmdLineModuleDirectoryWatcherPrivate::modulesChanged signal.
+   */
+  void onModulesChanged();
+
+private:
+
+  QScopedPointer d;
+  Q_DISABLE_COPY(ctkCmdLineModuleDirectoryWatcher)
+};
+
+#endif // __ctkCmdLineModuleDirectoryWatcher_h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
new file mode 100644
index 0000000000..4503a7ed98
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
@@ -0,0 +1,151 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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
+
+  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 __ctkCmdLineModuleDirectoryWatcherPrivate_h
+#define __ctkCmdLineModuleDirectoryWatcherPrivate_h
+
+#include 
+#include 
+#include 
+#include 
+
+#include "ctkCmdLineModuleReference.h"
+#include "ctkCmdLineModuleDirectoryWatcher.h"
+
+class QFileSystemWatcher;
+
+/**
+ * \class ctkCmdLineModuleDirectoryWatcherPrivate
+ * \brief Private implementation class implementing directory scanning to load new modules into a ctkCmdLineModuleManager.
+ * \ingroup CommandLineModulesCore
+ * \author m.clarkson@ucl.ac.uk
+ */
+class ctkCmdLineModuleDirectoryWatcherPrivate : public QObject
+{
+
+  Q_OBJECT
+
+public:
+
+  ctkCmdLineModuleDirectoryWatcherPrivate(ctkCmdLineModuleManager* ModuleManager);
+  virtual ~ctkCmdLineModuleDirectoryWatcherPrivate();
+
+  /**
+   * \see ctkCmdLineModuleDirectoryWatcher::setDebug
+   */
+  void setDebug(const bool& debug);
+
+  /**
+   * \see ctkCmdLineModuleDirectoryWatcher::setDirectories
+   */
+  void setDirectories(const QStringList& directories);
+
+  /**
+   * \see ctkCmdLineModuleDirectoryWatcher::directories
+   */
+  QStringList directories();
+
+  /**
+   * \see ctkCmdLineModuleDirectoryWatcher::files
+   */
+  QStringList files();
+
+  /**
+   * \see ctkCmdLineModuleDirectoryWatcher::filenameToReferenceMap
+   */
+  QHash filenameToReferenceMap() const;
+
+Q_SIGNALS:
+
+  /**
+   * \brief Used to signal to ctkCmdLineModuleDirectoryWatcher public class.
+   */
+  void modulesChanged();
+
+public Q_SLOTS:
+
+  /**
+   * \brief We connect QFileSystemWatcher to here.
+   */
+  void onFileChanged(const QString& path);
+
+  /**
+   * \brief We connect QFileSystemWatcher to here.
+   */
+  void onDirectoryChanged(const QString &path);
+
+private:
+
+  /**
+   * \brief Used to update the QFileSystemWatcher with the right list of directories and files to watch.
+   * \param directories list of absolute directory paths
+   * \param files list of absolute file paths
+   */
+  void updateWatchedPaths(const QStringList& directories, const QStringList& files);
+
+  /**
+   * \brief Takes a list of directories, and only returns ones that are valid,
+   * meaning that the directory name is non-null, non-empty, and the directory exists.
+   * \param directories a list of directories, relative or absolute.
+   * \return a list of directories, denoted by their absolute path.
+   */
+  QStringList filterInvalidDirectories(const QStringList& directories);
+
+  /**
+   * \brief Uses the MapFileNameToReference to work out a list of valid command line modules in a given directory.
+   * \param directory the absolute or relative path of a directory.
+   * \return a list of executables, denoted by their absolute path.
+   */
+  QStringList extractCurrentlyWatchedFilenamesInDirectory(const QString& directory);
+  QStringList getExecutablesInDirectory(const QString& directory);
+
+  /**
+   * \brief Main method to update the current list of watched directories and files.
+   * \param directories a list of directories, denoted by their absolute path.
+   */
+  void setModuleReferences(const QStringList &directories);
+
+  /**
+   * \brief Called from the onDirectoryChanged slot to update the current list by calling back to setModuleReferences.
+   * \param directory denoted by its absolute path.
+   */
+  void updateModuleReferences(const QString &directory);
+
+  /**
+   * \brief Uses the ctkCmdLineModuleManager to try and add the executable to the list
+   * of executables, and if successful it is added to this->MapFileNameToReference.
+   * \param pathToExecutable path to an executable file, denoted by its absolute path.
+   */
+  ctkCmdLineModuleReference loadModule(const QString& pathToExecutable);
+
+  /**
+   * \brief Removes the executable from both the ctkCmdLineModuleManager and this->MapFileNameToReference.
+   * \param pathToExecutable path to an executable file, denoted by its absolute path.
+   */
+  void unloadModule(const QString& pathToExecutable);
+
+  QHash MapFileNameToReference;
+  ctkCmdLineModuleManager* ModuleManager;
+  QFileSystemWatcher* FileSystemWatcher;
+  bool Debug;
+};
+
+#endif
+

From a15224d70a87a4301e168504d09e25a55cbb9dd0 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Wed, 18 Jul 2012 12:44:57 +0100
Subject: [PATCH 041/247] Added new class ctkCmdLineModuleMenuFactoryQtGui

---
 Libs/CommandLineModules/QtGui/CMakeLists.txt  |  2 +-
 .../ctkCmdLineModuleMenuFactoryQtGui.cpp      | 51 +++++++++++++++++++
 .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h  | 49 ++++++++++++++++++
 3 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
 create mode 100644 Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h

diff --git a/Libs/CommandLineModules/QtGui/CMakeLists.txt b/Libs/CommandLineModules/QtGui/CMakeLists.txt
index 71e64bbb4b..6098ef9f35 100644
--- a/Libs/CommandLineModules/QtGui/CMakeLists.txt
+++ b/Libs/CommandLineModules/QtGui/CMakeLists.txt
@@ -17,13 +17,13 @@ set(KIT_SRCS
   ctkCmdLineModuleInstanceFactoryQtGui.cpp
   ctkCmdLineModuleInstanceQtGui_p.h
   ctkCmdLineModuleInstanceQtGui.cpp
+  ctkCmdLineModuleMenuFactoryQtGui.cpp
   ctkCmdLineModuleObjectTreeWalker_p.h
   ctkCmdLineModuleObjectTreeWalker.cpp
 )
 
 # Headers that should run through moc
 set(KIT_MOC_SRCS
-  
 )
 
 # UI files
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
new file mode 100644
index 0000000000..c78a9f219b
--- /dev/null
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
@@ -0,0 +1,51 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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
+
+  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.
+
+=============================================================================*/
+
+#include "ctkCmdLineModuleMenuFactoryQtGui.h"
+#include "ctkCmdLineModuleDescription.h"
+#include 
+#include 
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleMenuFactoryQtGui::ctkCmdLineModuleMenuFactoryQtGui()
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleMenuFactoryQtGui::~ctkCmdLineModuleMenuFactoryQtGui()
+{
+
+}
+
+//-----------------------------------------------------------------------------
+QMenu* ctkCmdLineModuleMenuFactoryQtGui::create(const QHash& hashMap)
+{
+  QMenu *menu = new QMenu();
+  ctkCmdLineModuleReference ref;
+
+  QList references = hashMap.values();
+  foreach (ref, references)
+  {
+    menu->addAction(ref.description().title());
+  }
+  return menu;
+}
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
new file mode 100644
index 0000000000..d134073577
--- /dev/null
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
@@ -0,0 +1,49 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) University College London
+
+  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
+
+  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 CTKCMDLINEMODULEMENUFACTORYQTGUI_H
+#define CTKCMDLINEMODULEMENUFACTORYQTGUI_H
+
+#include 
+#include 
+#include "ctkCmdLineModuleReference.h"
+#include "ctkCommandLineModulesQtGuiExport.h"
+
+/**
+ * \class ctkCmdLineModuleMenuFactoryQtGui
+ * \brief Takes a QHash of filename and ctkCmdLineModuleReference and produces a QMenu.
+ * \author m.clarkson@ucl.ac.uk
+ */
+class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui
+{
+public:
+
+  ctkCmdLineModuleMenuFactoryQtGui();
+  virtual ~ctkCmdLineModuleMenuFactoryQtGui();
+
+  /**
+   * \brief Constructs a menu, for all the items in the QHash.
+   * \param hashMap Hash map of filename to reference.
+   * \return QMenu* a menu.
+   */
+  QMenu* create(const QHash& hashMap);
+};
+
+#endif // CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H

From c789e9959685edafd6e96d6288f9c74570a59491 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Thu, 19 Jul 2012 06:41:30 +0100
Subject: [PATCH 042/247] Menu Factory takes QList of ctkCmdLineModuleReference
 instead of QHash

---
 .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp              | 3 +--
 .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h                | 6 +++---
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
index c78a9f219b..4bcd25ff7f 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp
@@ -37,12 +37,11 @@ ctkCmdLineModuleMenuFactoryQtGui::~ctkCmdLineModuleMenuFactoryQtGui()
 }
 
 //-----------------------------------------------------------------------------
-QMenu* ctkCmdLineModuleMenuFactoryQtGui::create(const QHash& hashMap)
+QMenu* ctkCmdLineModuleMenuFactoryQtGui::create(const QList& references)
 {
   QMenu *menu = new QMenu();
   ctkCmdLineModuleReference ref;
 
-  QList references = hashMap.values();
   foreach (ref, references)
   {
     menu->addAction(ref.description().title());
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
index d134073577..5cbfcd73ec 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
@@ -22,7 +22,7 @@
 #define CTKCMDLINEMODULEMENUFACTORYQTGUI_H
 
 #include 
-#include 
+#include 
 #include "ctkCmdLineModuleReference.h"
 #include "ctkCommandLineModulesQtGuiExport.h"
 
@@ -40,10 +40,10 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui
 
   /**
    * \brief Constructs a menu, for all the items in the QHash.
-   * \param hashMap Hash map of filename to reference.
+   * \param list List of references, from which to build a menu.
    * \return QMenu* a menu.
    */
-  QMenu* create(const QHash& hashMap);
+  QMenu* create(const QList& list);
 };
 
 #endif // CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H

From 78344ec368474de9a3b7653339a2c18679a3219f Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Thu, 19 Jul 2012 06:43:18 +0100
Subject: [PATCH 043/247] Removed modulesChanged signal, and
 filenameToReferenceMap from ctkCmdLineModuleDirectoryWatcher

---
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp | 24 -------------------
 .../Core/ctkCmdLineModuleDirectoryWatcher.h   | 19 ---------------
 .../ctkCmdLineModuleDirectoryWatcherPrivate.h | 17 +++++--------
 3 files changed, 6 insertions(+), 54 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
index 1e9bd3c1f5..9dd6c1527d 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
@@ -36,7 +36,6 @@
 ctkCmdLineModuleDirectoryWatcher::ctkCmdLineModuleDirectoryWatcher(ctkCmdLineModuleManager* moduleManager)
   : d(new ctkCmdLineModuleDirectoryWatcherPrivate(moduleManager))
 {
-  connect(d.data(), SIGNAL(modulesChanged()), this, SLOT(onModulesChanged()));
 }
 
 
@@ -75,19 +74,6 @@ QStringList ctkCmdLineModuleDirectoryWatcher::files()
 }
 
 
-//-----------------------------------------------------------------------------
-QHash ctkCmdLineModuleDirectoryWatcher::filenameToReferenceMap() const
-{
-  return d->filenameToReferenceMap();
-}
-
-
-//-----------------------------------------------------------------------------
-void ctkCmdLineModuleDirectoryWatcher::onModulesChanged()
-{
-  emit modulesChanged();
-}
-
 //-----------------------------------------------------------------------------
 // ctkCmdLineModuleDirectoryWatcherPrivate methods
 
@@ -119,13 +105,6 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(const bool& debug)
 }
 
 
-//-----------------------------------------------------------------------------
-QHash ctkCmdLineModuleDirectoryWatcherPrivate::filenameToReferenceMap() const
-{
-  return this->MapFileNameToReference;
-}
-
-
 //-----------------------------------------------------------------------------
 QStringList ctkCmdLineModuleDirectoryWatcherPrivate::directories()
 {
@@ -146,7 +125,6 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setDirectories(const QStringList&
   QStringList validDirectories = this->filterInvalidDirectories(directories);
   this->setModuleReferences(validDirectories);
   this->updateWatchedPaths(validDirectories, this->MapFileNameToReference.keys());
-  emit modulesChanged();
 }
 
 
@@ -359,7 +337,6 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(const QString& path)
   if (ref)
   {
     if (this->Debug) qDebug() << "Reloaded " << path;
-    emit modulesChanged();
   }
   else
   {
@@ -381,7 +358,6 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::onDirectoryChanged(const QString &
     updateModuleReferences(path);
 
     if (this->Debug) qDebug() << "Reloaded modules in" << path;
-    emit modulesChanged();
   }
   else
   {
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
index 538f894c65..5ed04858bf 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
@@ -72,25 +72,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QOb
    */
   QStringList files();
 
-  /**
-   * \brief Retrieves a map of filenames (command line apps) and their command line module reference.
-   */
-  QHash filenameToReferenceMap() const;
-
-Q_SIGNALS:
-
-  /**
-   * \brief Signals that the modules have changed, so GUI's can re-build their menus.
-   */
-  void modulesChanged();
-
-private Q_SLOTS:
-
-  /**
-   * \brief Private slot, so we can connect to the ctkCmdLineModuleDirectoryWatcherPrivate::modulesChanged signal.
-   */
-  void onModulesChanged();
-
 private:
 
   QScopedPointer d;
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
index 4503a7ed98..4f85c74e3e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
@@ -67,17 +67,6 @@ class ctkCmdLineModuleDirectoryWatcherPrivate : public QObject
    */
   QStringList files();
 
-  /**
-   * \see ctkCmdLineModuleDirectoryWatcher::filenameToReferenceMap
-   */
-  QHash filenameToReferenceMap() const;
-
-Q_SIGNALS:
-
-  /**
-   * \brief Used to signal to ctkCmdLineModuleDirectoryWatcher public class.
-   */
-  void modulesChanged();
 
 public Q_SLOTS:
 
@@ -114,6 +103,12 @@ public Q_SLOTS:
    * \return a list of executables, denoted by their absolute path.
    */
   QStringList extractCurrentlyWatchedFilenamesInDirectory(const QString& directory);
+
+  /**
+   * \brief Returns a list of executable files (not necessarily valid command line clients) in a directory.
+   * \param directory A directory
+   * \return QStringList a list of absolute path names to executable files
+   */
   QStringList getExecutablesInDirectory(const QString& directory);
 
   /**

From 086955896c070ffc77783e6fa5aafeb9f28a3364 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Thu, 19 Jul 2012 06:43:43 +0100
Subject: [PATCH 044/247] Added moduleAdded and moduleRemoved to
 ctkCmdLineModuleManager

---
 Libs/CommandLineModules/Core/CMakeLists.txt            |  1 +
 .../Core/ctkCmdLineModuleManager.cpp                   |  5 ++++-
 Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h | 10 ++++++++--
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index 3e6fc4033c..d2a78855b6 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -45,6 +45,7 @@ set(KIT_SRCS
 set(KIT_MOC_SRCS
   ctkCmdLineModuleDirectoryWatcher.h
   ctkCmdLineModuleDirectoryWatcherPrivate.h
+  ctkCmdLineModuleManager.h
   ctkCmdLineModuleInstance.h
   ctkCmdLineModuleProcessTask.h
 )
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index f4352cb692..abe124f625 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -89,12 +89,15 @@ ctkCmdLineModuleManager::registerModule(const QString& location)
 //  ref.d->setGUI(descriptionFactory->createGUIFromXML(ref.d->xml));
 
   d->Cache[location] = ref;
+
+  emit moduleAdded(ref);
   return ref;
 }
 
 void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
 {
   d->Cache.remove(ref.location());
+  emit moduleRemoved(ref);
 }
 
 ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QString& location) const
@@ -104,7 +107,7 @@ ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QString
 
 QList ctkCmdLineModuleManager::moduleReferences() const
 {
-  throw ctkException("not implemented yet");
+  return d->Cache.values();
 }
 
 ctkCmdLineModuleInstance*
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
index ea06e141cb..5ec707bf20 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
@@ -26,18 +26,19 @@
 
 #include 
 #include 
+#include "ctkCmdLineModuleReference.h"
 
 struct ctkCmdLineModuleInstanceFactory;
 
 class ctkCmdLineModuleInstance;
-class ctkCmdLineModuleReference;
 class ctkCmdLineModuleManagerPrivate;
 
 /**
  * \ingroup CommandLineModulesCore
  */
-class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager
+class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
 {
+  Q_OBJECT
 
 public:
 
@@ -68,6 +69,11 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager
 
   QList moduleInstances(const ctkCmdLineModuleReference& moduleRef) const;
 
+Q_SIGNALS:
+
+  void moduleAdded(const ctkCmdLineModuleReference);
+  void moduleRemoved(const ctkCmdLineModuleReference);
+
 private:
 
   QScopedPointer d;

From f21b5f65b50d667d39743b3d9f7ed28b9fe7c2ca Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 17:47:47 +0200
Subject: [PATCH 045/247] Added setVerboseOutput() method to
 CmdLineModuleManager.

---
 Libs/CommandLineModules/Core/CMakeLists.txt   |  1 +
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp |  6 +++-
 .../Core/ctkCmdLineModuleManager.cpp          | 29 +++++++++++++++----
 .../Core/ctkCmdLineModuleManager.h            |  3 ++
 4 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index d2a78855b6..93d34170f2 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -18,6 +18,7 @@ set(KIT_SRCS
   ctkCmdLineModuleDescription.cpp
   ctkCmdLineModuleDescriptionPrivate.h
   ctkCmdLineModuleDirectoryWatcher.cpp
+  ctkCmdLineModuleDirectoryWatcherPrivate.h
   ctkCmdLineModuleInstance.cpp
   ctkCmdLineModuleInstanceFactory.cpp
   ctkCmdLineModuleManager.cpp
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
index 9dd6c1527d..7b1f912bf7 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
@@ -21,12 +21,14 @@
 #include "ctkCmdLineModuleDirectoryWatcher.h"
 #include "ctkCmdLineModuleDirectoryWatcherPrivate.h"
 #include "ctkCmdLineModuleManager.h"
+
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+
 #include 
 
 //-----------------------------------------------------------------------------
@@ -36,6 +38,7 @@
 ctkCmdLineModuleDirectoryWatcher::ctkCmdLineModuleDirectoryWatcher(ctkCmdLineModuleManager* moduleManager)
   : d(new ctkCmdLineModuleDirectoryWatcherPrivate(moduleManager))
 {
+  Q_ASSERT(moduleManager);
 }
 
 
@@ -102,6 +105,7 @@ ctkCmdLineModuleDirectoryWatcherPrivate::~ctkCmdLineModuleDirectoryWatcherPrivat
 void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(const bool& debug)
 {
   this->Debug = debug;
+  this->ModuleManager->setVerboseOutput(debug);
 }
 
 
@@ -309,7 +313,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateModuleReferences(const QStri
 //-----------------------------------------------------------------------------
 ctkCmdLineModuleReference ctkCmdLineModuleDirectoryWatcherPrivate::loadModule(const QString& pathToExecutable)
 {
-  ctkCmdLineModuleReference ref = this->ModuleManager->registerModule(pathToExecutable, !this->Debug);
+  ctkCmdLineModuleReference ref = this->ModuleManager->registerModule(pathToExecutable);
   if (ref)
   {
     this->MapFileNameToReference[pathToExecutable] = ref;
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index abe124f625..ea37b232ae 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -36,9 +36,14 @@
 
 struct ctkCmdLineModuleManagerPrivate
 {
+  ctkCmdLineModuleManagerPrivate()
+    : Verbose(false)
+  {}
+
   ctkCmdLineModuleInstanceFactory* InstanceFactory;
 
   QHash Cache;
+  bool Verbose;
 };
 
 ctkCmdLineModuleManager::ctkCmdLineModuleManager(ctkCmdLineModuleInstanceFactory *instanceFactory,
@@ -52,6 +57,16 @@ ctkCmdLineModuleManager::~ctkCmdLineModuleManager()
 {
 }
 
+void ctkCmdLineModuleManager::setVerboseOutput(bool verbose)
+{
+  d->Verbose = verbose;
+}
+
+bool ctkCmdLineModuleManager::verboseOutput() const
+{
+  return d->Verbose;
+}
+
 ctkCmdLineModuleReference
 ctkCmdLineModuleManager::registerModule(const QString& location)
 {
@@ -64,15 +79,16 @@ ctkCmdLineModuleManager::registerModule(const QString& location)
   if (!process.waitForFinished() || process.exitStatus() == QProcess::CrashExit ||
       process.error() != QProcess::UnknownError)
   {
-    qWarning() << "The executable at" << location << "could not be started:" << process.errorString();
+    if(d->Verbose)
+    {
+      qWarning() << "The executable at" << location << "could not be started:" << process.errorString();
+    }
     return ref;
   }
 
   process.waitForReadyRead();
   QByteArray xml = process.readAllStandardOutput();
 
-  qDebug() << xml;
-
   // validate the outputted xml description
   QBuffer input(&xml);
   input.open(QIODevice::ReadOnly);
@@ -80,13 +96,14 @@ ctkCmdLineModuleManager::registerModule(const QString& location)
   ctkCmdLineModuleXmlValidator validator(&input);
   if (!validator.validateInput())
   {
-    qCritical() << validator.errorString();
+    if(d->Verbose)
+    {
+      qWarning() << validator.errorString();
+    }
     return ref;
   }
 
   ref.d->RawXmlDescription = xml;
-//  ref.d->objectRepresentation = descriptionFactory->createObjectRepresentationFromXML(ref.d->xml);
-//  ref.d->setGUI(descriptionFactory->createGUIFromXML(ref.d->xml));
 
   d->Cache[location] = ref;
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
index 5ec707bf20..31eb57a1da 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
@@ -59,6 +59,9 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
 
   ~ctkCmdLineModuleManager();
 
+  void setVerboseOutput(bool verbose);
+  bool verboseOutput() const;
+
   ctkCmdLineModuleReference registerModule(const QString& location);
   void unregisterModule(const ctkCmdLineModuleReference& moduleRef);
 

From d7125ce87bd6ee33bf38e499d0e56888ecd7dedf Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 17:54:53 +0200
Subject: [PATCH 046/247] Use pass by value for primitive types. Added const
 where appropriate.

---
 .../ctkCmdLineModuleDefaultPathBuilder.cpp    | 24 +++++++++----------
 .../Core/ctkCmdLineModuleDefaultPathBuilder.h |  8 +++----
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp | 18 +++++++-------
 .../Core/ctkCmdLineModuleDirectoryWatcher.h   | 12 +++++-----
 .../ctkCmdLineModuleDirectoryWatcherPrivate.h | 12 +++++-----
 5 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp
index 3055ce98cb..f9ec4ee77e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp
@@ -32,10 +32,10 @@ struct ctkCmdLineModuleDefaultPathBuilderPrivate
   ~ctkCmdLineModuleDefaultPathBuilderPrivate();
   QStringList build() const;
 
-  void setLoadFromHomeDir(const bool& doLoad);
-  void setLoadFromCurrentDir(const bool& doLoad);
-  void setLoadFromApplicationDir(const bool& doLoad);
-  void setLoadFromCtkModuleLoadPath(const bool& doLoad);
+  void setLoadFromHomeDir(bool doLoad);
+  void setLoadFromCurrentDir(bool doLoad);
+  void setLoadFromApplicationDir(bool doLoad);
+  void setLoadFromCtkModuleLoadPath(bool doLoad);
 
   bool LoadFromHomeDir;
   bool LoadFromCurrentDir;
@@ -64,25 +64,25 @@ ctkCmdLineModuleDefaultPathBuilderPrivate::~ctkCmdLineModuleDefaultPathBuilderPr
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromHomeDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromHomeDir(bool doLoad)
 {
   LoadFromHomeDir = doLoad;
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCurrentDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCurrentDir(bool doLoad)
 {
   LoadFromCurrentDir = doLoad;
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromApplicationDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromApplicationDir(bool doLoad)
 {
   LoadFromApplicationDir = doLoad;
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCtkModuleLoadPath(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilderPrivate::setLoadFromCtkModuleLoadPath(bool doLoad)
 {
   LoadFromCtkModuleLoadPath = doLoad;
 }
@@ -156,25 +156,25 @@ QStringList ctkCmdLineModuleDefaultPathBuilder::build() const
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilder::setLoadFromHomeDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilder::setLoadFromHomeDir(bool doLoad)
 {
   d->setLoadFromHomeDir(doLoad);
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCurrentDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCurrentDir(bool doLoad)
 {
   d->setLoadFromCurrentDir(doLoad);
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilder::setLoadFromApplicationDir(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilder::setLoadFromApplicationDir(bool doLoad)
 {
   d->setLoadFromApplicationDir(doLoad);
 }
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCtkModuleLoadPath(const bool& doLoad)
+void ctkCmdLineModuleDefaultPathBuilder::setLoadFromCtkModuleLoadPath(bool doLoad)
 {
   d->setLoadFromCtkModuleLoadPath(doLoad);
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h
index 11064933b9..60e0bfe2fe 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h
@@ -57,13 +57,13 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDefaultPathBuilder
   ctkCmdLineModuleDefaultPathBuilder();
   ~ctkCmdLineModuleDefaultPathBuilder();
 
-  virtual void setLoadFromHomeDir(const bool& doLoad);
+  virtual void setLoadFromHomeDir(bool doLoad);
 
-  virtual void setLoadFromCurrentDir(const bool& doLoad);
+  virtual void setLoadFromCurrentDir(bool doLoad);
 
-  virtual void setLoadFromApplicationDir(const bool& doLoad);
+  virtual void setLoadFromApplicationDir(bool doLoad);
 
-  virtual void setLoadFromCtkModuleLoadPath(const bool& doLoad);
+  virtual void setLoadFromCtkModuleLoadPath(bool doLoad);
 
   virtual QStringList build() const;
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
index 7b1f912bf7..135a861911 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
@@ -50,7 +50,7 @@ ctkCmdLineModuleDirectoryWatcher::~ctkCmdLineModuleDirectoryWatcher()
 
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDirectoryWatcher::setDebug(const bool& debug)
+void ctkCmdLineModuleDirectoryWatcher::setDebug(bool debug)
 {
   d->setDebug(debug);
 }
@@ -64,14 +64,14 @@ void ctkCmdLineModuleDirectoryWatcher::setDirectories(const QStringList& directo
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcher::directories()
+QStringList ctkCmdLineModuleDirectoryWatcher::directories() const
 {
   return d->directories();
 }
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcher::files()
+QStringList ctkCmdLineModuleDirectoryWatcher::files() const
 {
   return d->files();
 }
@@ -102,7 +102,7 @@ ctkCmdLineModuleDirectoryWatcherPrivate::~ctkCmdLineModuleDirectoryWatcherPrivat
 
 
 //-----------------------------------------------------------------------------
-void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(const bool& debug)
+void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(bool debug)
 {
   this->Debug = debug;
   this->ModuleManager->setVerboseOutput(debug);
@@ -110,14 +110,14 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(const bool& debug)
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcherPrivate::directories()
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::directories() const
 {
   return this->FileSystemWatcher->directories();
 }
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcherPrivate::files()
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::files() const
 {
   return this->FileSystemWatcher->files();
 }
@@ -158,7 +158,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateWatchedPaths(const QStringLi
 }
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcherPrivate::filterInvalidDirectories(const QStringList& directories)
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::filterInvalidDirectories(const QStringList& directories) const
 {
   QStringList result;
 
@@ -180,7 +180,7 @@ QStringList ctkCmdLineModuleDirectoryWatcherPrivate::filterInvalidDirectories(co
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcherPrivate::extractCurrentlyWatchedFilenamesInDirectory(const QString& path)
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::extractCurrentlyWatchedFilenamesInDirectory(const QString& path) const
 {
   QStringList result;
 
@@ -205,7 +205,7 @@ QStringList ctkCmdLineModuleDirectoryWatcherPrivate::extractCurrentlyWatchedFile
 
 
 //-----------------------------------------------------------------------------
-QStringList ctkCmdLineModuleDirectoryWatcherPrivate::getExecutablesInDirectory(const QString& path)
+QStringList ctkCmdLineModuleDirectoryWatcherPrivate::getExecutablesInDirectory(const QString& path) const
 {
   QStringList result;
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
index 5ed04858bf..ea00efb63a 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h
@@ -22,11 +22,11 @@
 #define __ctkCmdLineModuleDirectoryWatcher_h
 
 #include 
+
+#include "ctkCmdLineModuleReference.h"
+
 #include 
-#include 
-#include 
 #include 
-#include "ctkCmdLineModuleReference.h"
 
 class ctkCmdLineModuleManager;
 class ctkCmdLineModuleDirectoryWatcherPrivate;
@@ -54,7 +54,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QOb
    * \brief Set the watcher into debug mode, for more output.
    * \param debug if true, you get more output, otherwise, less output.
    */
-  void setDebug(const bool& debug);
+  void setDebug(bool debug);
 
   /**
    * \brief Set the directories to be watched.
@@ -65,12 +65,12 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QOb
   /**
    * \brief Returns the list of directories currently being watched.
    */
-  QStringList directories();
+  QStringList directories() const;
 
   /**
    * \brief Returns the list of files (command line apps) currently being watched.
    */
-  QStringList files();
+  QStringList files() const;
 
 private:
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
index 4f85c74e3e..1c1f7456dd 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
@@ -50,7 +50,7 @@ class ctkCmdLineModuleDirectoryWatcherPrivate : public QObject
   /**
    * \see ctkCmdLineModuleDirectoryWatcher::setDebug
    */
-  void setDebug(const bool& debug);
+  void setDebug(bool debug);
 
   /**
    * \see ctkCmdLineModuleDirectoryWatcher::setDirectories
@@ -60,12 +60,12 @@ class ctkCmdLineModuleDirectoryWatcherPrivate : public QObject
   /**
    * \see ctkCmdLineModuleDirectoryWatcher::directories
    */
-  QStringList directories();
+  QStringList directories() const;
 
   /**
    * \see ctkCmdLineModuleDirectoryWatcher::files
    */
-  QStringList files();
+  QStringList files() const;
 
 
 public Q_SLOTS:
@@ -95,21 +95,21 @@ public Q_SLOTS:
    * \param directories a list of directories, relative or absolute.
    * \return a list of directories, denoted by their absolute path.
    */
-  QStringList filterInvalidDirectories(const QStringList& directories);
+  QStringList filterInvalidDirectories(const QStringList& directories) const;
 
   /**
    * \brief Uses the MapFileNameToReference to work out a list of valid command line modules in a given directory.
    * \param directory the absolute or relative path of a directory.
    * \return a list of executables, denoted by their absolute path.
    */
-  QStringList extractCurrentlyWatchedFilenamesInDirectory(const QString& directory);
+  QStringList extractCurrentlyWatchedFilenamesInDirectory(const QString& directory) const;
 
   /**
    * \brief Returns a list of executable files (not necessarily valid command line clients) in a directory.
    * \param directory A directory
    * \return QStringList a list of absolute path names to executable files
    */
-  QStringList getExecutablesInDirectory(const QString& directory);
+  QStringList getExecutablesInDirectory(const QString& directory) const;
 
   /**
    * \brief Main method to update the current list of watched directories and files.

From 261841d091f44e0853a58650145cdb08d0730679 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Thu, 19 Jul 2012 11:59:19 -0400
Subject: [PATCH 047/247] Put cache in independent database because of issue
 #204

Now there will be a ctkDICOMTagCache.txt in the same
directory with the ctkDICOMDatabase.sql that stores
the cached tags.
---
 .../Testing/Cpp/ctkDICOMDatabaseTest2.cpp     | 24 ++++---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp          | 69 +++++++++++++++----
 2 files changed, 69 insertions(+), 24 deletions(-)

diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp
index ddd71d9b83..aa1421f1fb 100644
--- a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp
+++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest2.cpp
@@ -46,6 +46,9 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
 
   ctkDICOMDatabase database;
   QDir databaseDirectory = QDir::temp();
+  databaseDirectory.remove("ctkDICOMDatabase.sql");
+  databaseDirectory.remove("ctkDICOMTagCache.sql");
+
   QFileInfo databaseFile(databaseDirectory, QString("database.test"));
   database.openDatabase(databaseFile.absoluteFilePath());
 
@@ -129,15 +132,6 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     }
 
 
-  QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE");
-
-  QString foundSeriesDescription = database.instanceValue(instanceUID, tag);
-
-  if (foundSeriesDescription != knownSeriesDescription)
-    {
-    std::cerr << "ctkDICOMDatabase: invalid element value returned" << std::endl;
-    return EXIT_FAILURE;
-    }
 
   //
   // Test the tag cache
@@ -161,12 +155,15 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
+
   if (database.cachedTag(instanceUID, tag) != QString(""))
     {
     std::cerr << "ctkDICOMDatabase: tag cache should return empty string for unknown instance tag" << std::endl;
     return EXIT_FAILURE;
     }
 
+  QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE");
+
   if (!database.cacheTag(instanceUID, tag, knownSeriesDescription))
     {
     std::cerr << "ctkDICOMDatabase: could not insert instance tag" << std::endl;
@@ -179,6 +176,15 @@ int ctkDICOMDatabaseTest2( int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
+
+  QString foundSeriesDescription = database.instanceValue(instanceUID, tag);
+
+  if (foundSeriesDescription != knownSeriesDescription)
+    {
+    std::cerr << "ctkDICOMDatabase: invalid element value returned" << std::endl;
+    return EXIT_FAILURE;
+    }
+
   database.closeDatabase();
   database.initializeDatabase();
 
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index c6809d54f3..634e56e724 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -21,19 +21,19 @@
 #include 
 
 // Qt includes
-#include 
-#include 
-#include 
-#include 
 #include 
-#include 
-#include 
-#include 
+#include 
 #include 
+#include 
 #include 
-#include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 
 // ctkDICOM includes
 #include "ctkDICOMDatabase.h"
@@ -109,6 +109,11 @@ class ctkDICOMDatabasePrivate
 
   /// tagCache table has been checked to exist
   bool TagCacheVerified;
+  /// tag cache has independent database to avoid locking issue
+  /// with other access to the database which need to be
+  /// reading while the tag cache is writing
+  QSqlDatabase TagCacheDatabase;
+  QString TagCacheDatabaseFilename;
 
   int insertPatient(const ctkDICOMDataset& ctkDataset);
   void insertStudy(const ctkDICOMDataset& ctkDataset, int dbPatientID);
@@ -133,6 +138,7 @@ void ctkDICOMDatabasePrivate::init(QString databaseFilename)
   Q_Q(ctkDICOMDatabase);
 
   q->openDatabase(databaseFilename);
+
 }
 
 //------------------------------------------------------------------------------
@@ -214,6 +220,11 @@ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& c
       QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList(databaseFile),this);
       connect(watcher, SIGNAL(fileChanged(QString)),this, SIGNAL (databaseChanged()) );
     }
+
+  // set up the tag cache for use later
+  QFileInfo fileInfo(d->DatabaseFileName);
+  d->TagCacheDatabaseFilename = QString( fileInfo.dir().path() + "/ctkDICOMTagCache.sql" );
+  d->TagCacheVerified = false;
 }
 
 
@@ -333,6 +344,7 @@ void ctkDICOMDatabase::closeDatabase()
 {
   Q_D(ctkDICOMDatabase);
   d->Database.close();
+  d->TagCacheDatabase.close();
 }
 
 //
@@ -1196,13 +1208,32 @@ bool ctkDICOMDatabase::tagCacheExists()
     {
     return true;
     }
-  QSqlQuery cacheExists( d->Database );
+
+  // try to open the database if it's not already open
+  if ( !(d->TagCacheDatabase.isOpen()) )
+    {
+    qDebug() << "TagCacheDatabase not open\n";
+    d->TagCacheDatabase = QSqlDatabase::addDatabase("QSQLITE", "TagCache");
+    d->TagCacheDatabase.setDatabaseName(d->TagCacheDatabaseFilename);
+    if ( !(d->TagCacheDatabase.open()) )
+      {
+      qDebug() << "TagCacheDatabase would not open!\n";
+      qDebug() << "TagCacheDatabaseFilename is: " << d->TagCacheDatabaseFilename << "\n";
+      return false;
+      }
+    }
+
+  // check that the table exists
+  QSqlQuery cacheExists( d->TagCacheDatabase );
   cacheExists.prepare("SELECT * FROM TagCache LIMIT 1");
   bool success = d->loggedExec(cacheExists);
   if (success)
     {
+    qDebug() << "TagCacheDatabase verified!\n";
     d->TagCacheVerified = true;
+    return true;
     }
+  qDebug() << "TagCacheDatabase NOT verified based on table check!\n";
   return false;
 }
 
@@ -1214,13 +1245,15 @@ bool ctkDICOMDatabase::initializeTagCache()
   // First, drop any existing table
   if ( this->tagCacheExists() )
     {
-    QSqlQuery dropCacheTable( d->Database );
+    qDebug() << "TagCacheDatabase drop existing table\n";
+    QSqlQuery dropCacheTable( d->TagCacheDatabase );
     dropCacheTable.prepare( "DROP TABLE TagCache" );
     d->loggedExec(dropCacheTable);
     }
 
   // now create a table
-  QSqlQuery createCacheTable( d->Database );
+  qDebug() << "TagCacheDatabase adding table\n";
+  QSqlQuery createCacheTable( d->TagCacheDatabase );
   createCacheTable.prepare(
     "CREATE TABLE TagCache (SOPInstanceUID, Tag, Value, PRIMARY KEY (SOPInstanceUID, Tag))" );
   bool success = d->loggedExec(createCacheTable);
@@ -1238,9 +1271,12 @@ QString ctkDICOMDatabase::cachedTag(const QString sopInstanceUID, const QString
   Q_D(ctkDICOMDatabase);
   if ( !this->tagCacheExists() )
     {
-    this->initializeTagCache();
+    if ( !this->initializeTagCache() )
+      {
+      return( "" );
+      }
     }
-  QSqlQuery selectValue( d->Database );
+  QSqlQuery selectValue( d->TagCacheDatabase );
   selectValue.prepare( "SELECT Value FROM TagCache WHERE SOPInstanceUID = :sopInstanceUID AND Tag = :tag" );
   selectValue.bindValue(":sopInstanceUID",sopInstanceUID);
   selectValue.bindValue(":tag",tag);
@@ -1259,9 +1295,12 @@ bool ctkDICOMDatabase::cacheTag(const QString sopInstanceUID, const QString tag,
   Q_D(ctkDICOMDatabase);
   if ( !this->tagCacheExists() )
     {
-    this->initializeTagCache();
+    if ( !this->initializeTagCache() )
+      {
+      return false;
+      }
     }
-  QSqlQuery insertTag( d->Database );
+  QSqlQuery insertTag( d->TagCacheDatabase );
   insertTag.prepare( "INSERT OR REPLACE INTO TagCache VALUES(:sopInstanceUID, :tag, :value)" );
   insertTag.bindValue(":sopInstanceUID",sopInstanceUID);
   insertTag.bindValue(":tag",tag);

From c7c82f0f92dc438e010e62098ea022387d712bca Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 18:12:21 +0200
Subject: [PATCH 048/247] Consistently use _p.h for private headers.

---
 Libs/CommandLineModules/Core/CMakeLists.txt   | 10 ++--
 .../Core/ctkCmdLineModuleDescription.cpp      |  2 +-
 ...vate.h => ctkCmdLineModuleDescription_p.h} |  0
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp |  2 +-
 ...h => ctkCmdLineModuleDirectoryWatcher_p.h} |  0
 .../Core/ctkCmdLineModuleManager.cpp          |  2 +-
 .../Core/ctkCmdLineModuleParameter.cpp        | 28 ++++++++++-
 .../Core/ctkCmdLineModuleParameterGroup.cpp   |  2 +-
 ...e.h => ctkCmdLineModuleParameterGroup_p.h} |  0
 .../Core/ctkCmdLineModuleParameterParsers_p.h |  2 +-
 .../Core/ctkCmdLineModuleParameterPrivate.cpp | 46 -------------------
 ...rivate.h => ctkCmdLineModuleParameter_p.h} |  0
 .../Core/ctkCmdLineModuleReference.cpp        | 18 +++++++-
 .../Core/ctkCmdLineModuleReferencePrivate.cpp | 39 ----------------
 ...rivate.h => ctkCmdLineModuleReference_p.h} |  0
 .../Core/ctkCmdLineModuleXmlParser.cpp        |  4 +-
 16 files changed, 55 insertions(+), 100 deletions(-)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleDescriptionPrivate.h => ctkCmdLineModuleDescription_p.h} (100%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleDirectoryWatcherPrivate.h => ctkCmdLineModuleDirectoryWatcher_p.h} (100%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleParameterGroupPrivate.h => ctkCmdLineModuleParameterGroup_p.h} (100%)
 delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.cpp
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleParameterPrivate.h => ctkCmdLineModuleParameter_p.h} (100%)
 delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.cpp
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleReferencePrivate.h => ctkCmdLineModuleReference_p.h} (100%)

diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index 93d34170f2..433bd9c904 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -16,22 +16,20 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT")
 set(KIT_SRCS
   ctkCmdLineModuleDefaultPathBuilder.cpp
   ctkCmdLineModuleDescription.cpp
-  ctkCmdLineModuleDescriptionPrivate.h
+  ctkCmdLineModuleDescription_p.h
   ctkCmdLineModuleDirectoryWatcher.cpp
-  ctkCmdLineModuleDirectoryWatcherPrivate.h
+  ctkCmdLineModuleDirectoryWatcher_p.h
   ctkCmdLineModuleInstance.cpp
   ctkCmdLineModuleInstanceFactory.cpp
   ctkCmdLineModuleManager.cpp
   ctkCmdLineModuleParameter.cpp
-  ctkCmdLineModuleParameterPrivate.cpp
   ctkCmdLineModuleParameterGroup.cpp
-  ctkCmdLineModuleParameterGroupPrivate.h
+  ctkCmdLineModuleParameterGroup_p.h
   ctkCmdLineModuleParameterParsers_p.h
   ctkCmdLineModulePathBuilder.cpp
   ctkCmdLineModuleProcessTask.cpp
   ctkCmdLineModuleXmlProgressWatcher.cpp
   ctkCmdLineModuleReference.cpp
-  ctkCmdLineModuleReferencePrivate.cpp
   ctkCmdLineModuleRunException.cpp
   ctkCmdLineModuleXmlException.cpp
   ctkCmdLineModuleXmlMsgHandler_p.h
@@ -45,7 +43,7 @@ set(KIT_SRCS
 # Headers that should run through moc
 set(KIT_MOC_SRCS
   ctkCmdLineModuleDirectoryWatcher.h
-  ctkCmdLineModuleDirectoryWatcherPrivate.h
+  ctkCmdLineModuleDirectoryWatcher_p.h
   ctkCmdLineModuleManager.h
   ctkCmdLineModuleInstance.h
   ctkCmdLineModuleProcessTask.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.cpp
index 606eafdd4d..273b4e13bf 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.cpp
@@ -19,7 +19,7 @@ limitations under the License.
 =============================================================================*/
 
 #include "ctkCmdLineModuleDescription.h"
-#include "ctkCmdLineModuleDescriptionPrivate.h"
+#include "ctkCmdLineModuleDescription_p.h"
 
 #include "ctkCmdLineModuleParameter.h"
 #include "ctkCmdLineModuleParameterGroup.h"
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescriptionPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription_p.h
similarity index 100%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleDescriptionPrivate.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleDescription_p.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
index 135a861911..6b8f403608 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp
@@ -19,7 +19,7 @@
 =============================================================================*/
 
 #include "ctkCmdLineModuleDirectoryWatcher.h"
-#include "ctkCmdLineModuleDirectoryWatcherPrivate.h"
+#include "ctkCmdLineModuleDirectoryWatcher_p.h"
 #include "ctkCmdLineModuleManager.h"
 
 #include 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h
similarity index 100%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcherPrivate.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index ea37b232ae..f9202a68fe 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -23,7 +23,7 @@
 
 #include "ctkCmdLineModuleXmlValidator.h"
 #include "ctkCmdLineModuleReference.h"
-#include "ctkCmdLineModuleReferencePrivate.h"
+#include "ctkCmdLineModuleReference_p.h"
 #include "ctkCmdLineModuleInstanceFactory.h"
 
 #include 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp
index 1a8f0d9a61..b216512ffb 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp
@@ -20,11 +20,37 @@ limitations under the License.
 
 #include "ctkCmdLineModuleParameter.h"
 
-#include "ctkCmdLineModuleParameterPrivate.h"
+#include "ctkCmdLineModuleParameter_p.h"
 
 #include 
 #include 
 
+//----------------------------------------------------------------------------
+ctkCmdLineModuleParameterPrivate::ctkCmdLineModuleParameterPrivate()
+  : Hidden(false), Constraints(false), Index(-1), Multiple(false), Aggregate("false")
+{}
+
+//----------------------------------------------------------------------------
+QStringList ctkCmdLineModuleParameterPrivate::splitAndTrim(const QString& str, const QString& separator)
+{
+  QStringList l = str.split(separator, QString::SkipEmptyParts);
+  l.removeDuplicates();
+  // trim the strings
+  QMutableStringListIterator i(l);
+  while(i.hasNext())
+  {
+    QString& n = i.next();
+    n = n.trimmed();
+  }
+  return l;
+}
+
+//----------------------------------------------------------------------------
+void ctkCmdLineModuleParameterPrivate::setFileExtensionsAsString(const QString& extensions)
+{
+  FileExtensions = splitAndTrim(extensions, ",");
+  FileExtensionsAsString = FileExtensions.join(",");
+}
 
 //----------------------------------------------------------------------------
 ctkCmdLineModuleParameter::ctkCmdLineModuleParameter()
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.cpp
index 1a2edb2f33..a22d4f0c0d 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.cpp
@@ -21,7 +21,7 @@ limitations under the License.
 #include "ctkCmdLineModuleParameterGroup.h"
 
 #include "ctkCmdLineModuleParameter.h"
-#include "ctkCmdLineModuleParameterGroupPrivate.h"
+#include "ctkCmdLineModuleParameterGroup_p.h"
 
 #include "ctkException.h"
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroupPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup_p.h
similarity index 100%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroupPrivate.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup_p.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h
index a561189060..98c437ff6d 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h
@@ -25,7 +25,7 @@
 #include 
 
 #include "ctkCmdLineModuleParameter.h"
-#include "ctkCmdLineModuleParameterPrivate.h"
+#include "ctkCmdLineModuleParameter_p.h"
 
 namespace {
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.cpp
deleted file mode 100644
index 49e5382674..0000000000
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  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
-    
-  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.
-  
-=============================================================================*/
-
-#include "ctkCmdLineModuleParameterPrivate.h"
-
-ctkCmdLineModuleParameterPrivate::ctkCmdLineModuleParameterPrivate()
-  : Hidden(false), Constraints(false), Index(-1), Multiple(false), Aggregate("false")
-{}
-
-QStringList ctkCmdLineModuleParameterPrivate::splitAndTrim(const QString& str, const QString& separator)
-{
-  QStringList l = str.split(separator, QString::SkipEmptyParts);
-  l.removeDuplicates();
-  // trim the strings
-  QMutableStringListIterator i(l);
-  while(i.hasNext())
-  {
-    QString& n = i.next();
-    n = n.trimmed();
-  }
-  return l;
-}
-
-void ctkCmdLineModuleParameterPrivate::setFileExtensionsAsString(const QString& extensions)
-{
-  FileExtensions = splitAndTrim(extensions, ",");
-  FileExtensionsAsString = FileExtensions.join(",");
-}
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h
similarity index 100%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleParameterPrivate.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp
index fd60290f5e..c59ffc5521 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp
@@ -20,7 +20,23 @@
 =============================================================================*/
 
 #include "ctkCmdLineModuleReference.h"
-#include "ctkCmdLineModuleReferencePrivate.h"
+#include "ctkCmdLineModuleReference_p.h"
+#include "ctkCmdLineModuleXmlParser_p.h"
+
+#include 
+
+ctkCmdLineModuleDescription ctkCmdLineModuleReferencePrivate::description() const
+{
+  // Lazy creation. The title is a required XML element.
+  if (Description.title().isNull())
+  {
+    QByteArray xml(RawXmlDescription);
+    QBuffer xmlInput(&xml);
+    ctkCmdLineModuleXmlParser parser(&xmlInput, &Description);
+    parser.doParse();
+  }
+  return Description;
+}
 
 ctkCmdLineModuleReference::ctkCmdLineModuleReference()
   : d(new ctkCmdLineModuleReferencePrivate())
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.cpp
deleted file mode 100644
index 2ea7e291c3..0000000000
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  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
-    
-  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.
-  
-=============================================================================*/
-
-#include "ctkCmdLineModuleReferencePrivate.h"
-#include "ctkCmdLineModuleXmlParser_p.h"
-
-#include 
-
-ctkCmdLineModuleDescription ctkCmdLineModuleReferencePrivate::description() const
-{
-  // Lazy creation. The title is a requirement XML element.
-  if (Description.title().isNull())
-  {
-    QByteArray xml(RawXmlDescription);
-    QBuffer xmlInput(&xml);
-    ctkCmdLineModuleXmlParser parser(&xmlInput, &Description);
-    parser.doParse();
-  }
-  return Description;
-}
-
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h
similarity index 100%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleReferencePrivate.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp
index f5a706c237..eb0df1ddb2 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp
@@ -28,9 +28,9 @@ limitations under the License.
 // CTK includes
 #include "ctkCmdLineModuleXmlParser_p.h"
 #include "ctkCmdLineModuleDescription.h"
-#include "ctkCmdLineModuleDescriptionPrivate.h"
+#include "ctkCmdLineModuleDescription_p.h"
 #include "ctkCmdLineModuleParameterGroup.h"
-#include "ctkCmdLineModuleParameterGroupPrivate.h"
+#include "ctkCmdLineModuleParameterGroup_p.h"
 #include "ctkCmdLineModuleParameterParsers_p.h"
 
 #include "ctkCmdLineModuleXmlException.h"

From 19409f4d86eb1b8878f7718ccc0eb0ee865269fd Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 18:32:21 +0200
Subject: [PATCH 049/247] Renamed files and classes from *ModuleInstance* to
 *Module*.

---
 .../ctkCLModuleExplorerMainWindow.cpp         | 22 +++++++--------
 .../ctkCLModuleExplorerMainWindow.h           |  2 +-
 Libs/CommandLineModules/Core/CMakeLists.txt   |  6 ++--
 .../Cpp/ctkCmdLineModuleFutureTest.cpp        | 18 ++++++------
 ...oduleInstance.cpp => ctkCmdLineModule.cpp} | 28 +++++++++----------
 ...ineModuleInstance.h => ctkCmdLineModule.h} | 18 ++++++------
 ...actory.cpp => ctkCmdLineModuleFactory.cpp} |  4 +--
 ...nceFactory.h => ctkCmdLineModuleFactory.h} | 14 +++++-----
 .../Core/ctkCmdLineModuleManager.cpp          | 14 +++++-----
 .../Core/ctkCmdLineModuleManager.h            | 10 +++----
 Libs/CommandLineModules/QtGui/CMakeLists.txt  |  6 ++--
 ...i.cpp => ctkCmdLineModuleFactoryQtGui.cpp} | 10 +++----
 ...QtGui.h => ctkCmdLineModuleFactoryQtGui.h} | 14 +++++-----
 .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h  |  2 +-
 ...nceQtGui.cpp => ctkCmdLineModuleQtGui.cpp} | 16 +++++------
 ...nceQtGui_p.h => ctkCmdLineModuleQtGui_p.h} | 14 +++++-----
 16 files changed, 99 insertions(+), 99 deletions(-)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleInstance.cpp => ctkCmdLineModule.cpp} (81%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleInstance.h => ctkCmdLineModule.h} (79%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleInstanceFactory.cpp => ctkCmdLineModuleFactory.cpp} (88%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleInstanceFactory.h => ctkCmdLineModuleFactory.h} (72%)
 rename Libs/CommandLineModules/QtGui/{ctkCmdLineModuleInstanceFactoryQtGui.cpp => ctkCmdLineModuleFactoryQtGui.cpp} (75%)
 rename Libs/CommandLineModules/QtGui/{ctkCmdLineModuleInstanceFactoryQtGui.h => ctkCmdLineModuleFactoryQtGui.h} (69%)
 rename Libs/CommandLineModules/QtGui/{ctkCmdLineModuleInstanceQtGui.cpp => ctkCmdLineModuleQtGui.cpp} (81%)
 rename Libs/CommandLineModules/QtGui/{ctkCmdLineModuleInstanceQtGui_p.h => ctkCmdLineModuleQtGui_p.h} (78%)

diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
index e62a309e39..c597d21221 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
@@ -24,8 +24,8 @@
 
 #include 
 #include 
-#include 
-#include 
+#include 
+#include 
 #include 
 
 #include 
@@ -34,7 +34,7 @@
 ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::ctkCLModuleExplorerMainWindow),
-  moduleManager(new ctkCmdLineModuleInstanceFactoryQtGui())
+  moduleManager(new ctkCmdLineModuleFactoryQtGui())
 {
   ui->setupUi(this);
 }
@@ -46,14 +46,14 @@ ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow()
 
 void ctkCLModuleExplorerMainWindow::addModuleTab(const ctkCmdLineModuleReference& moduleRef)
 {
-  ctkCmdLineModuleInstance* moduleInstance = moduleManager.createModuleInstance(moduleRef);
-  if (!moduleInstance) return;
+  ctkCmdLineModule* module = moduleManager.createModule(moduleRef);
+  if (!module) return;
 
-  QObject* guiHandle = moduleInstance->guiHandle();
+  QObject* guiHandle = module->guiHandle();
 
   QWidget* widget = qobject_cast(guiHandle);
   int tabIndex = ui->mainTabWidget->addTab(widget, widget->objectName());
-  mapTabToModuleRef[tabIndex] = moduleInstance;
+  mapTabToModuleRef[tabIndex] = module;
 }
 
 void ctkCLModuleExplorerMainWindow::addModule(const QString &location)
@@ -67,17 +67,17 @@ void ctkCLModuleExplorerMainWindow::addModule(const QString &location)
 
 void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
 {
-  ctkCmdLineModuleInstance* moduleInstance = mapTabToModuleRef[ui->mainTabWidget->currentIndex()];
-  if (!moduleInstance)
+  ctkCmdLineModule* module = mapTabToModuleRef[ui->mainTabWidget->currentIndex()];
+  if (!module)
   {
     qWarning() << "Invalid module instance";
     return;
   }
 
-  QStringList cmdLineArgs = moduleInstance->commandLineArguments();
+  QStringList cmdLineArgs = module->commandLineArguments();
   qDebug() << cmdLineArgs;
 
-  QFuture future = moduleInstance->run();
+  QFuture future = module->run();
   try
   {
     future.waitForFinished();
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
index c7e3e88125..8e32a4e9ab 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
@@ -63,7 +63,7 @@ protected Q_SLOTS:
 
   ctkCmdLineModuleManager moduleManager;
 
-  QHash mapTabToModuleRef;
+  QHash mapTabToModuleRef;
 
   //ctkCmdLineModuleProcessFutureWatcher futureWatcher;
 };
diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index 433bd9c904..93a0e82f1a 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -19,8 +19,8 @@ set(KIT_SRCS
   ctkCmdLineModuleDescription_p.h
   ctkCmdLineModuleDirectoryWatcher.cpp
   ctkCmdLineModuleDirectoryWatcher_p.h
-  ctkCmdLineModuleInstance.cpp
-  ctkCmdLineModuleInstanceFactory.cpp
+  ctkCmdLineModule.cpp
+  ctkCmdLineModuleFactory.cpp
   ctkCmdLineModuleManager.cpp
   ctkCmdLineModuleParameter.cpp
   ctkCmdLineModuleParameterGroup.cpp
@@ -45,7 +45,7 @@ set(KIT_MOC_SRCS
   ctkCmdLineModuleDirectoryWatcher.h
   ctkCmdLineModuleDirectoryWatcher_p.h
   ctkCmdLineModuleManager.h
-  ctkCmdLineModuleInstance.h
+  ctkCmdLineModule.h
   ctkCmdLineModuleProcessTask.h
 )
 
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
index 51f3b1a554..7bb1c29b8c 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
@@ -20,8 +20,8 @@
 =============================================================================*/
 
 #include 
-#include 
-#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -40,15 +40,15 @@
 #include 
 
 
-class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleInstanceFactory
+class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleFactory
 {
 public:
 
-  virtual ctkCmdLineModuleInstance* create(const ctkCmdLineModuleReference& moduleRef)
+  virtual ctkCmdLineModule* create(const ctkCmdLineModuleReference& moduleRef)
   {
-    struct ModuleTestInstance : public ctkCmdLineModuleInstance
+    struct ModuleTestInstance : public ctkCmdLineModule
     {
-      ModuleTestInstance(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleInstance(moduleRef) {}
+      ModuleTestInstance(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModule(moduleRef) {}
 
       virtual QObject* guiHandle() const { return NULL; }
 
@@ -82,7 +82,7 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
     qCritical() << "Module at" << moduleFilename << "could not be registered";
   }
 
-  ctkCmdLineModuleInstance* moduleInstance = manager.createModuleInstance(moduleRef);
+  ctkCmdLineModule* module = manager.createModule(moduleRef);
 
   QList expectedSignals;
   expectedSignals.push_back("module.started");
@@ -94,7 +94,7 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
-  QFuture future = moduleInstance->run();
+  QFuture future = module->run();
   watcher.setFuture(future);
 
   future.waitForFinished();
@@ -102,7 +102,7 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
   // process pending events
   QCoreApplication::processEvents();
 
-  delete moduleInstance;
+  delete module;
 
   if (!signalTester.checkSignals(expectedSignals))
   {
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
similarity index 81%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
rename to Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
index 8c8f416de4..21ddb473d2 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
@@ -19,7 +19,7 @@
   
 =============================================================================*/
 
-#include "ctkCmdLineModuleInstance.h"
+#include "ctkCmdLineModule.h"
 #include "ctkCmdLineModuleDescription.h"
 #include "ctkCmdLineModuleParameter.h"
 #include "ctkCmdLineModuleParameterGroup.h"
@@ -33,9 +33,9 @@
 #include 
 #include 
 
-struct ctkCmdLineModuleInstancePrivate
+struct ctkCmdLineModulePrivate
 {
-  ctkCmdLineModuleInstancePrivate(ctkCmdLineModuleInstance* qq,
+  ctkCmdLineModulePrivate(ctkCmdLineModule* qq,
                                   const ctkCmdLineModuleReference& moduleRef)
     : ModuleReference(moduleRef), q(qq)
   {
@@ -53,21 +53,21 @@ struct ctkCmdLineModuleInstancePrivate
 
 private:
 
-  ctkCmdLineModuleInstance* q;
+  ctkCmdLineModule* q;
 
 };
 
 
-ctkCmdLineModuleInstance::ctkCmdLineModuleInstance(const ctkCmdLineModuleReference& moduleRef)
-  : d(new ctkCmdLineModuleInstancePrivate(this, moduleRef))
+ctkCmdLineModule::ctkCmdLineModule(const ctkCmdLineModuleReference& moduleRef)
+  : d(new ctkCmdLineModulePrivate(this, moduleRef))
 {
 }
 
-ctkCmdLineModuleInstance::~ctkCmdLineModuleInstance()
+ctkCmdLineModule::~ctkCmdLineModule()
 {
 }
 
-QList ctkCmdLineModuleInstance::parameterNames() const
+QList ctkCmdLineModule::parameterNames() const
 {
   if (!d->ParameterNames.isEmpty()) return d->ParameterNames;
 
@@ -82,17 +82,17 @@ QList ctkCmdLineModuleInstance::parameterNames() const
   return d->ParameterNames;
 }
 
-ctkCmdLineModuleReference ctkCmdLineModuleInstance::moduleReference() const
+ctkCmdLineModuleReference ctkCmdLineModule::moduleReference() const
 {
   return d->ModuleReference;
 }
 
-QString ctkCmdLineModuleInstance::location() const
+QString ctkCmdLineModule::location() const
 {
   return d->ModuleReference.location();
 }
 
-QStringList ctkCmdLineModuleInstance::commandLineArguments() const
+QStringList ctkCmdLineModule::commandLineArguments() const
 {
   QStringList cmdLineArgs;
   QHash indexedArgs;
@@ -147,7 +147,7 @@ QStringList ctkCmdLineModuleInstance::commandLineArguments() const
   return cmdLineArgs;
 }
 
-QFuture ctkCmdLineModuleInstance::run() const
+QFuture ctkCmdLineModule::run() const
 {
   QStringList args = commandLineArguments();
 
@@ -159,7 +159,7 @@ QFuture ctkCmdLineModuleInstance::run() const
 }
 
 
-QHash ctkCmdLineModuleInstance::values() const
+QHash ctkCmdLineModule::values() const
 {
   QHash result;
   foreach(QString parameterName, parameterNames())
@@ -169,7 +169,7 @@ QHash ctkCmdLineModuleInstance::values() const
   return result;
 }
 
-void ctkCmdLineModuleInstance::setValues(const QHash &values)
+void ctkCmdLineModule::setValues(const QHash &values)
 {
   QHashIterator iter(values);
   while(iter.hasNext())
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
similarity index 79%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModule.h
index bd5a898854..cda0070b80 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstance.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
@@ -19,8 +19,8 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEINSTANCE_H
-#define CTKCMDLINEMODULEINSTANCE_H
+#ifndef CTKCMDLINEMODULE_H
+#define CTKCMDLINEMODULE_H
 
 #include "ctkCommandLineModulesCoreExport.h"
 
@@ -30,18 +30,18 @@ template class QHash;
 template class QFuture;
 
 class ctkCmdLineModuleReference;
-class ctkCmdLineModuleInstancePrivate;
+class ctkCmdLineModulePrivate;
 
 /**
  * \ingroup CommandLineModulesCore
  */
-class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleInstance : public QObject
+class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModule : public QObject
 {
   Q_OBJECT
 
 public:
 
-  ~ctkCmdLineModuleInstance();
+  ~ctkCmdLineModule();
 
   virtual QObject* guiHandle() const = 0;
 
@@ -65,14 +65,14 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleInstance : public QObject
 
 protected:
 
-  ctkCmdLineModuleInstance(const ctkCmdLineModuleReference& moduleRef);
+  ctkCmdLineModule(const ctkCmdLineModuleReference& moduleRef);
 
 private:
 
-  friend class ctkCmdLineModuleInstancePrivate;
+  friend class ctkCmdLineModulePrivate;
 
-  QScopedPointer d;
+  QScopedPointer d;
 
 };
 
-#endif // CTKCMDLINEMODULEINSTANCE_H
+#endif // CTKCMDLINEMODULE_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp
similarity index 88%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.cpp
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp
index 268b52706a..1cd22579c1 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp
@@ -19,8 +19,8 @@
   
 =============================================================================*/
 
-#include "ctkCmdLineModuleInstanceFactory.h"
+#include "ctkCmdLineModuleFactory.h"
 
-ctkCmdLineModuleInstanceFactory::~ctkCmdLineModuleInstanceFactory()
+ctkCmdLineModuleFactory::~ctkCmdLineModuleFactory()
 {
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h
similarity index 72%
rename from Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.h
rename to Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h
index aa1d9fff5f..69438c7b54 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleInstanceFactory.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h
@@ -19,22 +19,22 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEINSTANCEFACTORY_H
-#define CTKCMDLINEMODULEINSTANCEFACTORY_H
+#ifndef CTKCMDLINEMODULEFACTORY_H
+#define CTKCMDLINEMODULEFACTORY_H
 
 #include "ctkCommandLineModulesCoreExport.h"
 
-class ctkCmdLineModuleInstance;
+class ctkCmdLineModule;
 class ctkCmdLineModuleReference;
 
 /**
  * \ingroup CommandLineModulesCore
  */
-struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleInstanceFactory
+struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFactory
 {
-  virtual ~ctkCmdLineModuleInstanceFactory();
+  virtual ~ctkCmdLineModuleFactory();
 
-  virtual ctkCmdLineModuleInstance* create(const ctkCmdLineModuleReference& moduleInstance) = 0;
+  virtual ctkCmdLineModule* create(const ctkCmdLineModuleReference& module) = 0;
 };
 
-#endif // CTKCMDLINEMODULEINSTANCEFACTORY_H
+#endif // CTKCMDLINEMODULEFACTORY_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index f9202a68fe..d2452f674b 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -24,7 +24,7 @@
 #include "ctkCmdLineModuleXmlValidator.h"
 #include "ctkCmdLineModuleReference.h"
 #include "ctkCmdLineModuleReference_p.h"
-#include "ctkCmdLineModuleInstanceFactory.h"
+#include "ctkCmdLineModuleFactory.h"
 
 #include 
 
@@ -40,13 +40,13 @@ struct ctkCmdLineModuleManagerPrivate
     : Verbose(false)
   {}
 
-  ctkCmdLineModuleInstanceFactory* InstanceFactory;
+  ctkCmdLineModuleFactory* InstanceFactory;
 
   QHash Cache;
   bool Verbose;
 };
 
-ctkCmdLineModuleManager::ctkCmdLineModuleManager(ctkCmdLineModuleInstanceFactory *instanceFactory,
+ctkCmdLineModuleManager::ctkCmdLineModuleManager(ctkCmdLineModuleFactory *instanceFactory,
                                                  ValidationMode validationMode)
   : d(new ctkCmdLineModuleManagerPrivate)
 {
@@ -127,14 +127,14 @@ QList ctkCmdLineModuleManager::moduleReferences() con
   return d->Cache.values();
 }
 
-ctkCmdLineModuleInstance*
-ctkCmdLineModuleManager::createModuleInstance(const ctkCmdLineModuleReference& moduleRef)
+ctkCmdLineModule*
+ctkCmdLineModuleManager::createModule(const ctkCmdLineModuleReference& moduleRef)
 {
   return d->InstanceFactory->create(moduleRef);
 }
 
-QList
-ctkCmdLineModuleManager::moduleInstances(const ctkCmdLineModuleReference& moduleRef) const
+QList
+ctkCmdLineModuleManager::modules(const ctkCmdLineModuleReference& moduleRef) const
 {
   throw ctkException("not implemented yet");
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
index 31eb57a1da..426f4abf2c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
@@ -28,9 +28,9 @@
 #include 
 #include "ctkCmdLineModuleReference.h"
 
-struct ctkCmdLineModuleInstanceFactory;
+struct ctkCmdLineModuleFactory;
 
-class ctkCmdLineModuleInstance;
+class ctkCmdLineModule;
 class ctkCmdLineModuleManagerPrivate;
 
 /**
@@ -54,7 +54,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
     WEAK_VALIDATION
   };
 
-  ctkCmdLineModuleManager(ctkCmdLineModuleInstanceFactory* descriptionFactory,
+  ctkCmdLineModuleManager(ctkCmdLineModuleFactory* descriptionFactory,
                           ValidationMode = STRICT_VALIDATION);
 
   ~ctkCmdLineModuleManager();
@@ -68,9 +68,9 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
   ctkCmdLineModuleReference moduleReference(const QString& location) const;
   QList moduleReferences() const;
 
-  ctkCmdLineModuleInstance* createModuleInstance(const ctkCmdLineModuleReference& moduleRef);
+  ctkCmdLineModule* createModule(const ctkCmdLineModuleReference& moduleRef);
 
-  QList moduleInstances(const ctkCmdLineModuleReference& moduleRef) const;
+  QList modules(const ctkCmdLineModuleReference& moduleRef) const;
 
 Q_SIGNALS:
 
diff --git a/Libs/CommandLineModules/QtGui/CMakeLists.txt b/Libs/CommandLineModules/QtGui/CMakeLists.txt
index 6098ef9f35..45fadf1664 100644
--- a/Libs/CommandLineModules/QtGui/CMakeLists.txt
+++ b/Libs/CommandLineModules/QtGui/CMakeLists.txt
@@ -14,9 +14,9 @@ set(KIT_export_directive "CTK_CMDLINEMODULEQTGUI_EXPORT")
 
 # Source files
 set(KIT_SRCS
-  ctkCmdLineModuleInstanceFactoryQtGui.cpp
-  ctkCmdLineModuleInstanceQtGui_p.h
-  ctkCmdLineModuleInstanceQtGui.cpp
+  ctkCmdLineModuleFactoryQtGui.cpp
+  ctkCmdLineModuleQtGui_p.h
+  ctkCmdLineModuleQtGui.cpp
   ctkCmdLineModuleMenuFactoryQtGui.cpp
   ctkCmdLineModuleObjectTreeWalker_p.h
   ctkCmdLineModuleObjectTreeWalker.cpp
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp
similarity index 75%
rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.cpp
rename to Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp
index a9f25b3869..fe56cb7014 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp
@@ -19,11 +19,11 @@
 
 =============================================================================*/
 
-#include "ctkCmdLineModuleInstanceFactoryQtGui.h"
-#include "ctkCmdLineModuleInstanceQtGui_p.h"
+#include "ctkCmdLineModuleFactoryQtGui.h"
+#include "ctkCmdLineModuleQtGui_p.h"
 
-ctkCmdLineModuleInstance*
-ctkCmdLineModuleInstanceFactoryQtGui::create(const ctkCmdLineModuleReference& moduleRef)
+ctkCmdLineModule*
+ctkCmdLineModuleFactoryQtGui::create(const ctkCmdLineModuleReference& moduleRef)
 {
-  return new ctkCmdLineModuleInstanceQtGui(moduleRef);
+  return new ctkCmdLineModuleQtGui(moduleRef);
 }
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h
similarity index 69%
rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.h
rename to Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h
index 352a2aa883..4293b46a6f 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceFactoryQtGui.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h
@@ -19,20 +19,20 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H
-#define CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H
+#ifndef CTKCMDLINEMODULEFACTORYQTGUI_H
+#define CTKCMDLINEMODULEFACTORYQTGUI_H
 
-#include "ctkCmdLineModuleInstanceFactory.h"
+#include "ctkCmdLineModuleFactory.h"
 
 #include "ctkCommandLineModulesQtGuiExport.h"
 
-class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleInstanceFactoryQtGui
-    : public ctkCmdLineModuleInstanceFactory
+class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFactoryQtGui
+    : public ctkCmdLineModuleFactory
 {
 public:
 
-  ctkCmdLineModuleInstance* create(const ctkCmdLineModuleReference& moduleRef);
+  ctkCmdLineModule* create(const ctkCmdLineModuleReference& moduleRef);
 
 };
 
-#endif // CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H
+#endif // CTKCMDLINEMODULEFACTORYQTGUI_H
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
index 5cbfcd73ec..2ae730e4ea 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
@@ -46,4 +46,4 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui
   QMenu* create(const QList& list);
 };
 
-#endif // CTKCMDLINEMODULEINSTANCEFACTORYQTGUI_H
+#endif // CTKCMDLINEMODULEFACTORYQTGUI_H
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
similarity index 81%
rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui.cpp
rename to Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
index 22c94cd835..cdf7abb54e 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
@@ -19,7 +19,7 @@
   
 =============================================================================*/
 
-#include "ctkCmdLineModuleInstanceQtGui_p.h"
+#include "ctkCmdLineModuleQtGui_p.h"
 #include "ctkCmdLineModuleReference.h"
 #include "ctkCmdLineModuleXslTransform.h"
 #include "ctkCmdLineModuleObjectTreeWalker_p.h"
@@ -31,13 +31,13 @@
 
 #include 
 
-ctkCmdLineModuleInstanceQtGui::ctkCmdLineModuleInstanceQtGui(const ctkCmdLineModuleReference& moduleRef)
-  : ctkCmdLineModuleInstance(moduleRef),
+ctkCmdLineModuleQtGui::ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef)
+  : ctkCmdLineModule(moduleRef),
     WidgetTree(NULL)
 {
 }
 
-QObject* ctkCmdLineModuleInstanceQtGui::guiHandle() const
+QObject* ctkCmdLineModuleQtGui::guiHandle() const
 {
   if (WidgetTree) return WidgetTree;
 
@@ -59,7 +59,7 @@ QObject* ctkCmdLineModuleInstanceQtGui::guiHandle() const
   return WidgetTree;
 }
 
-QVariant ctkCmdLineModuleInstanceQtGui::value(const QString ¶meter) const
+QVariant ctkCmdLineModuleQtGui::value(const QString ¶meter) const
 {
   if (!WidgetTree) return QVariant();
 
@@ -74,7 +74,7 @@ QVariant ctkCmdLineModuleInstanceQtGui::value(const QString ¶meter) const
   return QVariant();
 }
 
-void ctkCmdLineModuleInstanceQtGui::setValue(const QString ¶meter, const QVariant &value)
+void ctkCmdLineModuleQtGui::setValue(const QString ¶meter, const QVariant &value)
 {
   if (!WidgetTree) return;
 
@@ -89,7 +89,7 @@ void ctkCmdLineModuleInstanceQtGui::setValue(const QString ¶meter, const QVa
   }
 }
 
-QList ctkCmdLineModuleInstanceQtGui::parameterNames() const
+QList ctkCmdLineModuleQtGui::parameterNames() const
 {
   if (!ParameterNames.empty()) return ParameterNames;
 
@@ -97,7 +97,7 @@ QList ctkCmdLineModuleInstanceQtGui::parameterNames() const
   // if it has already created (otherwise fall back to the superclass
   // implementation.
   // This avoids creating a ctkCmdLineModuleDescription instance.
-  if (WidgetTree == 0) return ctkCmdLineModuleInstance::parameterNames();
+  if (WidgetTree == 0) return ctkCmdLineModule::parameterNames();
 
   ctkCmdLineModuleObjectTreeWalker walker(WidgetTree);
   while(walker.readNextParameter())
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui_p.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
similarity index 78%
rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui_p.h
rename to Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
index 420c398fbd..00f8794b93 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleInstanceQtGui_p.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
@@ -19,21 +19,21 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEINSTANCEQTGUI_H
-#define CTKCMDLINEMODULEINSTANCEQTGUI_H
+#ifndef CTKCMDLINEMODULEQTGUI_H
+#define CTKCMDLINEMODULEQTGUI_H
 
-#include 
+#include 
 
 class ctkCmdLineModuleReference;
 
-class ctkCmdLineModuleInstanceQtGui : public ctkCmdLineModuleInstance
+class ctkCmdLineModuleQtGui : public ctkCmdLineModule
 {
 
 public:
 
-  ctkCmdLineModuleInstanceQtGui(const ctkCmdLineModuleReference& moduleRef);
+  ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef);
 
-  // ctkCmdLineModuleInstance overrides
+  // ctkCmdLineModule overrides
 
   virtual QObject* guiHandle() const;
 
@@ -50,4 +50,4 @@ class ctkCmdLineModuleInstanceQtGui : public ctkCmdLineModuleInstance
   mutable QList ParameterNames;
 };
 
-#endif // CTKCMDLINEMODULEINSTANCEQTGUI_H
+#endif // CTKCMDLINEMODULEQTGUI_H

From 1a1beb644c1527fd06f49cc1069c8eed4cb5291b Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 18:34:10 +0200
Subject: [PATCH 050/247] Fixed typo for consistent include guard names.

---
 .../CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
index 2ae730e4ea..fb1b1d0a36 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h
@@ -46,4 +46,4 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui
   QMenu* create(const QList& list);
 };
 
-#endif // CTKCMDLINEMODULEFACTORYQTGUI_H
+#endif // CTKCMDLINEMODULEMENUFACTORYQTGUI_H

From 9f07597ed4ed16a0ed20b10ca4bf1b975e2a88eb Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 19 Jul 2012 18:42:58 +0200
Subject: [PATCH 051/247] Removed superfluous semicolon.

---
 Libs/Widgets/ctkDirectoryListView.h     | 6 +++---
 Libs/Widgets/ctkDirectoryListWidget.h   | 4 ++--
 Libs/Widgets/ctkDirectoryListWidget_p.h | 2 +-
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/Libs/Widgets/ctkDirectoryListView.h b/Libs/Widgets/ctkDirectoryListView.h
index 97f8b8d88d..072395f442 100644
--- a/Libs/Widgets/ctkDirectoryListView.h
+++ b/Libs/Widgets/ctkDirectoryListView.h
@@ -35,7 +35,7 @@ class ctkDirectoryListViewPrivate;
 class CTK_WIDGETS_EXPORT ctkDirectoryListView : public QWidget
 {
   Q_OBJECT
-  Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList NOTIFY directoryListChanged);
+  Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList NOTIFY directoryListChanged)
 public:
   /// Superclass typedef
   typedef QWidget Superclass;
@@ -87,8 +87,8 @@ public slots:
   QScopedPointer d_ptr;
 
 private:
-  Q_DECLARE_PRIVATE(ctkDirectoryListView);
-  Q_DISABLE_COPY(ctkDirectoryListView);
+  Q_DECLARE_PRIVATE(ctkDirectoryListView)
+  Q_DISABLE_COPY(ctkDirectoryListView)
 
 };
 
diff --git a/Libs/Widgets/ctkDirectoryListWidget.h b/Libs/Widgets/ctkDirectoryListWidget.h
index d7cb992844..163b689d6e 100644
--- a/Libs/Widgets/ctkDirectoryListWidget.h
+++ b/Libs/Widgets/ctkDirectoryListWidget.h
@@ -62,8 +62,8 @@ public Q_SLOTS:
   QScopedPointer d_ptr;
 
 private:
-  Q_DECLARE_PRIVATE(ctkDirectoryListWidget);
-  Q_DISABLE_COPY(ctkDirectoryListWidget);
+  Q_DECLARE_PRIVATE(ctkDirectoryListWidget)
+  Q_DISABLE_COPY(ctkDirectoryListWidget)
 };
 
 #endif
diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkDirectoryListWidget_p.h
index 09a54188cf..ece88ba231 100644
--- a/Libs/Widgets/ctkDirectoryListWidget_p.h
+++ b/Libs/Widgets/ctkDirectoryListWidget_p.h
@@ -35,7 +35,7 @@
 class ctkDirectoryListWidgetPrivate : public QObject, public Ui_ctkDirectoryListWidget
 {
   Q_OBJECT
-  Q_DECLARE_PUBLIC(ctkDirectoryListWidget);
+  Q_DECLARE_PUBLIC(ctkDirectoryListWidget)
 protected:
   ctkDirectoryListWidget* const q_ptr;
 public:

From 383de183b2a0222361f365cb6ba0c38f0e4d8331 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Thu, 19 Jul 2012 15:54:58 -0400
Subject: [PATCH 052/247] Update CTKConfig to include CTK_CMAKE_UTILITIES_DIR
 in CMake module path

See issue #205
---
 CMake/CTKConfig.cmake.in | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/CMake/CTKConfig.cmake.in b/CMake/CTKConfig.cmake.in
index 3c5171f038..3cfe783329 100644
--- a/CMake/CTKConfig.cmake.in
+++ b/CMake/CTKConfig.cmake.in
@@ -154,6 +154,14 @@ SET(CTK_USE_FILE "@CTK_USE_FILE@")
 SET(CTK_CMAKE_DIR "@CTK_CMAKE_DIR_CONFIG@")
 SET(CTK_CMAKE_UTILITIES_DIR "@CTK_CMAKE_UTILITIES_DIR_CONFIG@")
 
+# Update CMake module path so that calling "find_package(DCMTK)" works as expected 
+# after calling "find_package(CTK)"
+# Ideally projects like DCMTK or PythonQt should provide both "Config" and "Use" files.
+set(CMAKE_MODULE_PATH
+  ${CTK_CMAKE_UTILITIES_DIR}
+  ${CMAKE_MODULE_PATH}
+  )
+
 # TODO The list of available libraries.
 
 # TODO The list of available plugins.

From 77805079f4bd50b7276480f14f000ae3f23309a8 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Fri, 20 Jul 2012 00:16:55 -0400
Subject: [PATCH 053/247] Library depending on debug build of PythonQt will
 link against correct python library

Since CTK now depends on the 'patched-2' branch of PythonQt, this is
required to ensure the _DEBUG macro will be undefined
within PythonQtPythonInclude.h. By undefining _DEBUG, both PythonQt or any
library linking against it can successfully link against release
python library.

See https://github.com/commontk/PythonQt/blob/6366f002a93aa238c55f58de949d09c552cda5a9/src/PythonQtPythonInclude.h#L62

This will fix error like the following:

19>3>5>Generating moc_ctkVTKConnection.cxx
19>3>4>LINK : fatal error LNK1104: cannot open file 'python26_d.lib'

See issue #203
---
 Utilities/CMake/FindPythonQt.cmake | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Utilities/CMake/FindPythonQt.cmake b/Utilities/CMake/FindPythonQt.cmake
index 82c38ecf81..8abc05b419 100644
--- a/Utilities/CMake/FindPythonQt.cmake
+++ b/Utilities/CMake/FindPythonQt.cmake
@@ -25,6 +25,9 @@ endif()
 
 set(PYTHONQT_FOUND 0)
 if(PYTHONQT_INCLUDE_DIR AND PYTHONQT_LIBRARY)
+  # Currently CMake'ified PythonQt only supports building against a python Release build. 
+  # This applies independently of CTK build type (Release, Debug, ...)
+  add_definitions(-DPYTHONQT_USE_RELEASE_PYTHON_FALLBACK)
   set(PYTHONQT_FOUND 1)
   set(PYTHONQT_LIBRARIES ${PYTHONQT_LIBRARY} ${PYTHONQT_LIBUTIL})
 endif()

From 6db4e7bb18bdffb6626cfd841507a22d2e475930 Mon Sep 17 00:00:00 2001
From: Michael Bauer 
Date: Fri, 20 Jul 2012 14:47:04 +0200
Subject: [PATCH 054/247] Prefer CMOVE operation in query/retrieve

---
 Libs/DICOM/Core/ctkDICOMQuery.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMQuery.cpp b/Libs/DICOM/Core/ctkDICOMQuery.cpp
index 088a4787d8..a0a57252fa 100644
--- a/Libs/DICOM/Core/ctkDICOMQuery.cpp
+++ b/Libs/DICOM/Core/ctkDICOMQuery.cpp
@@ -109,7 +109,7 @@ ctkDICOMQueryPrivate::ctkDICOMQueryPrivate()
   this->Query = new DcmDataset();
   this->Port = 0;
   this->Canceled = false;
-  this->PreferCGET = true;
+  this->PreferCGET = false;
 }
 
 //------------------------------------------------------------------------------

From a50e2dcc60eb2891a6c5d0d0a1505d0049d13f12 Mon Sep 17 00:00:00 2001
From: Michael Bauer 
Date: Fri, 20 Jul 2012 14:48:25 +0200
Subject: [PATCH 055/247] No database needed for retrieve

---
 Libs/DICOM/Core/ctkDICOMRetrieve.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMRetrieve.cpp b/Libs/DICOM/Core/ctkDICOMRetrieve.cpp
index 1e67e9ce40..0d94f25a68 100644
--- a/Libs/DICOM/Core/ctkDICOMRetrieve.cpp
+++ b/Libs/DICOM/Core/ctkDICOMRetrieve.cpp
@@ -216,11 +216,6 @@ bool ctkDICOMRetrievePrivate::initializeSCU( const QString& studyInstanceUID,
                                          const RetrieveType retrieveType,
                                          DcmDataset *retrieveParameters)
 {
-  if ( !this->Database )
-    {
-    logger.error ( "No Database for retrieve transaction" );
-    return false;
-    }
 
   // If we like to query another server than before, be sure to disconnect first
   if (this->SCU.isConnected() && this->ConnectionParamsChanged)

From 60c966cdefcff0eb5c0b357626728483c3b04164 Mon Sep 17 00:00:00 2001
From: Michael Bauer 
Date: Fri, 20 Jul 2012 14:50:10 +0200
Subject: [PATCH 056/247] Added boolean flag to make progress dialog popup
 optional

---
 .../Widgets/ctkDICOMQueryRetrieveWidget.cpp   | 36 +++++++++++++------
 .../Widgets/ctkDICOMQueryRetrieveWidget.h     |  2 ++
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
index ec277b7cdd..699d61efb9 100644
--- a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
@@ -68,6 +68,7 @@ class ctkDICOMQueryRetrieveWidgetPrivate: public Ui_ctkDICOMQueryRetrieveWidget
   
   QProgressDialog*                  ProgressDialog;
   QString                           CurrentServer;
+    bool                              UseProgressDialog;
 };
 
 //----------------------------------------------------------------------------
@@ -146,6 +147,12 @@ QSharedPointer ctkDICOMQueryRetrieveWidget::retrieveDatabase()
   return d->RetrieveDatabase;
 }
 
+void ctkDICOMQueryRetrieveWidget::useProgressDialog(bool enable)
+{
+    Q_D(ctkDICOMQueryRetrieveWidget);
+    d->UseProgressDialog=enable;
+}
+
 //----------------------------------------------------------------------------
 void ctkDICOMQueryRetrieveWidget::query()
 {
@@ -163,7 +170,6 @@ void ctkDICOMQueryRetrieveWidget::query()
   }
 
   d->QueriesByStudyUID.clear();
-
   // for each of the selected server nodes, send the query
   QProgressDialog progress("Query DICOM servers", "Cancel", 0, 100, this,
                            Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
@@ -256,6 +262,7 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   // We don't want the progress dialog to resize itself, so we bypass the label
   // by creating our own
   QLabel* progressLabel = new QLabel(tr("Initialization..."));
+    if(d->UseProgressDialog){
   progress.setLabel(progressLabel);
   d->ProgressDialog = &progress;
   progress.setWindowModality(Qt::ApplicationModal);
@@ -264,6 +271,7 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   progress.setMaximum(0);
   progress.setAutoClose(false);
   progress.show();
+    }
 
   QMap serverParameters = d->ServerNodeWidget->parameters();
   ctkDICOMRetrieve *retrieve = new ctkDICOMRetrieve;
@@ -275,6 +283,7 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
   // do the rerieval for each selected series
   foreach( QString studyUID, d->QueriesByStudyUID.keys() )
     {
+        if(d->UseProgressDialog){
     if (progress.wasCanceled())
       {
       break;
@@ -282,6 +291,7 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
 
     progressLabel->setText(QString(tr("Retrieving:\n%1")).arg(studyUID));
     this->updateRetrieveProgress(0);
+        }
 
     // Get information which server we want to get the study from and prepare request accordingly
     ctkDICOMQuery *query = d->QueriesByStudyUID[studyUID];
@@ -295,12 +305,13 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
     logger.debug("About to retrieve " + studyUID + " from " + d->QueriesByStudyUID[studyUID]->host());
     logger.info ( "Starting to retrieve" );
 
+        if(d->UseProgressDialog){
     connect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel()));
     connect(retrieve, SIGNAL(progress(QString)),
             progressLabel, SLOT(setText(QString)));
     connect(retrieve, SIGNAL(progress(int)),
             this, SLOT(updateRetrieveProgress(int)));
-
+        }
     try
       {
       // perform the retrieve
@@ -316,6 +327,7 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
     catch (std::exception e)
       {
       logger.error ( "Retrieve failed" );
+            if(d->UseProgressDialog){
       if ( QMessageBox::question ( this, 
             tr("Query Retrieve"), tr("Retrieve failed.  Keep trying?"),
             QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
@@ -327,13 +339,15 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
         break;
         }
       }
+        }
 
+        if(d->UseProgressDialog){
     disconnect(retrieve, SIGNAL(progress(QString)),
             progressLabel, SLOT(setText(QString)));
     disconnect(retrieve, SIGNAL(progress(int)),
             this, SLOT(updateRetrieveProgress(int)));
     disconnect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel()));
-
+        }
     // Store retrieve structure for later use.
     // Comment MO: I do not think that makes much sense; you store per study one fat
     // structure including an SCU. Also, I switched the code to re-use the retrieve
@@ -343,13 +357,15 @@ void ctkDICOMQueryRetrieveWidget::retrieve()
     // d->RetrievalsByStudyUID[studyUID] = retrieve;
     logger.info ( "Retrieve success" );
     }
-
-  QString message(tr("Retrieve Process Finished"));
-  if (retrieve->wasCanceled())
-    {
-    message = tr("Retrieve Process Canceled");
-    }
-  QMessageBox::information ( this, tr("Query Retrieve"), message );
+  if(d->UseProgressDialog)
+  {
+    QString message(tr("Retrieve Process Finished"));
+    if (retrieve->wasCanceled())
+      {
+      message = tr("Retrieve Process Canceled");
+      }
+    QMessageBox::information ( this, tr("Query Retrieve"), message );
+  }
   emit studiesRetrieved(d->RetrievalsByStudyUID.keys());
 
   delete retrieve;
diff --git a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
index eefb14a83c..21bdad6b2e 100644
--- a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
@@ -44,6 +44,8 @@ Q_OBJECT;
 
   QSharedPointer retrieveDatabase()const;
 
+  /// enable or disable ctk progress bars
+  void                   useProgressDialog(bool enable);
 public Q_SLOTS:
   void setRetrieveDatabase(QSharedPointer retrieveDatabase);
   void query();

From 9580f7b63c40a645976a8514b3186386244d2589 Mon Sep 17 00:00:00 2001
From: Michael Bauer 
Date: Fri, 20 Jul 2012 14:50:37 +0200
Subject: [PATCH 057/247] New method getServerParameters

---
 Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp | 5 +++++
 Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h   | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
index 699d61efb9..93afd6677f 100644
--- a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp
@@ -443,3 +443,8 @@ void ctkDICOMQueryRetrieveWidget::onSelectionChanged(const QItemSelection &selec
   d->RetrieveButton->setEnabled(d->results->selectionModel()->hasSelection());
 }
 
+QMap ctkDICOMQueryRetrieveWidget::getServerParameters()
+{
+    Q_D(ctkDICOMQueryRetrieveWidget);
+    return d->ServerNodeWidget->parameters();
+}
diff --git a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
index 21bdad6b2e..e585b9e4ed 100644
--- a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.h
@@ -26,6 +26,9 @@
 // Qt includes 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 
 // CTK includes
@@ -41,11 +44,13 @@ Q_OBJECT;
   typedef QWidget Superclass;
   explicit ctkDICOMQueryRetrieveWidget(QWidget* parent=0);
   virtual ~ctkDICOMQueryRetrieveWidget();
+  QMap getServerParameters();
 
   QSharedPointer retrieveDatabase()const;
 
   /// enable or disable ctk progress bars
   void                   useProgressDialog(bool enable);
+
 public Q_SLOTS:
   void setRetrieveDatabase(QSharedPointer retrieveDatabase);
   void query();

From 7775c377f5ddccd2c64cf39229c3ee9bbc5f1400 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 23 Jul 2012 09:38:32 +0200
Subject: [PATCH 058/247] Added support for progress reporting via QFuture.

---
 Libs/CommandLineModules/Core/CMakeLists.txt   |   3 +
 .../Cpp/ctkCmdLineModuleFutureTest.cpp        | 147 +++++++++++---
 .../Cpp/ctkCmdLineModuleSignalTester.cpp      |  24 ++-
 .../Cpp/ctkCmdLineModuleSignalTester.h        |  15 +-
 ...ctkCmdLineModuleXmlProgressWatcherTest.cpp | 185 ++++++++++++++++--
 .../TestBed/ctkCmdLineModuleTestBed.cpp       |  41 +++-
 .../TestBed/ctkCmdLineModuleTestBed.xml       |   7 +
 .../Core/ctkCmdLineModule.cpp                 |  12 +-
 .../Core/ctkCmdLineModule.h                   |   4 +-
 .../Core/ctkCmdLineModuleFuture.h             | 173 ++++++++++++++++
 .../Core/ctkCmdLineModuleFutureInterface.h    | 176 +++++++++++++++++
 .../Core/ctkCmdLineModuleProcessTask.cpp      |  94 ++++++---
 .../Core/ctkCmdLineModuleProcessTask.h        |  47 +++--
 .../Core/ctkCmdLineModuleResult.h             |  47 +++++
 .../Core/ctkCmdLineModuleRunException.cpp     |  32 ++-
 .../Core/ctkCmdLineModuleRunException.h       |  21 +-
 .../ctkCmdLineModuleXmlProgressWatcher.cpp    | 147 ++++++++------
 17 files changed, 1017 insertions(+), 158 deletions(-)
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h

diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt
index 93a0e82f1a..0f3e876293 100644
--- a/Libs/CommandLineModules/Core/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/CMakeLists.txt
@@ -21,6 +21,8 @@ set(KIT_SRCS
   ctkCmdLineModuleDirectoryWatcher_p.h
   ctkCmdLineModule.cpp
   ctkCmdLineModuleFactory.cpp
+  ctkCmdLineModuleFuture.h
+  ctkCmdLineModuleFutureInterface.h
   ctkCmdLineModuleManager.cpp
   ctkCmdLineModuleParameter.cpp
   ctkCmdLineModuleParameterGroup.cpp
@@ -28,6 +30,7 @@ set(KIT_SRCS
   ctkCmdLineModuleParameterParsers_p.h
   ctkCmdLineModulePathBuilder.cpp
   ctkCmdLineModuleProcessTask.cpp
+  ctkCmdLineModuleResult.h
   ctkCmdLineModuleXmlProgressWatcher.cpp
   ctkCmdLineModuleReference.cpp
   ctkCmdLineModuleRunException.cpp
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
index 7bb1c29b8c..20f09318ac 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
@@ -25,16 +25,14 @@
 #include 
 #include 
 #include 
-
-#include 
-#include 
+#include 
+#include 
 
 #include "ctkCmdLineModuleSignalTester.h"
 
 #include 
 #include 
 #include 
-#include 
 #include 
 
 #include 
@@ -54,47 +52,84 @@ class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleFactory
 
       virtual QVariant value(const QString& parameter) const
       {
-        return this->moduleReference().description().parameter(parameter).defaultValue();
+        QVariant value = currentValues[parameter];
+        if (!value.isValid())
+          return this->moduleReference().description().parameter(parameter).defaultValue();
+        return value;
       }
 
-      virtual void setValue(const QString& /*parameter*/, const QVariant& /*value*/)
+      virtual void setValue(const QString& parameter, const QVariant& value)
       {
-        // do nothing
+        currentValues[parameter] = value;
       }
+
+    private:
+
+      QHash currentValues;
     };
 
     return new ModuleTestInstance(moduleRef);
   }
 };
 
-
-int ctkCmdLineModuleFutureTest(int argc, char* argv[])
+bool futureTestStartFinish(ctkCmdLineModule* module)
 {
-  QCoreApplication app(argc, argv);
+  qDebug() << "Testing ctkCmdLineModuleFuture start/finish signals.";
 
-  ctkCmdLineModuleTestInstanceFactory factory;
-  ctkCmdLineModuleManager manager(&factory);
+  QList expectedSignals;
+  expectedSignals.push_back("module.started");
+  expectedSignals.push_back("module.finished");
 
-  QString moduleFilename = app.applicationDirPath() + "/ctkCmdLineModuleTestBed";
-  ctkCmdLineModuleReference moduleRef = manager.registerModule(moduleFilename);
-  if (!moduleRef)
-  {
-    qCritical() << "Module at" << moduleFilename << "could not be registered";
-  }
+  ctkCmdLineModuleSignalTester signalTester;
+
+  QFutureWatcher watcher;
+  QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
+  QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
+
+  ctkCmdLineModuleFuture future = module->run();
+  watcher.setFuture(future);
+
+  future.waitForFinished();
 
-  ctkCmdLineModule* module = manager.createModule(moduleRef);
+  // process pending events
+  QCoreApplication::processEvents();
+
+  return signalTester.checkSignals(expectedSignals);
+}
+
+bool futureTestProgress(ctkCmdLineModule* module)
+{
+  qDebug() << "Testing ctkCmdLineModuleFuture progress signals.";
 
   QList expectedSignals;
   expectedSignals.push_back("module.started");
+  // this signal is send when connecting a QFutureWatcher to
+  // an already started QFuture
+  expectedSignals.push_back("module.progressValueChanged");
+
+  // the following two signals are send when the module reports "filter start"
+  expectedSignals.push_back("module.progressValueChanged");
+  expectedSignals.push_back("module.progressTextChanged");
+
+  // this signal is send when the module reports progress for "output1"
+  expectedSignals.push_back("module.progressValueChanged");
+
+  // the following two signal are sent at the end to report
+  // completion and the full standard output text.
+  expectedSignals.push_back("module.progressValueChanged");
+  expectedSignals.push_back("module.progressTextChanged");
   expectedSignals.push_back("module.finished");
 
   ctkCmdLineModuleSignalTester signalTester;
 
-  QFutureWatcher watcher;
+  QFutureWatcher watcher;
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
+  QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &signalTester, SLOT(moduleProgressValueChanged(int)));
+  QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
-  QFuture future = module->run();
+  module->setValue("fileVar", "output1");
+  ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
 
   future.waitForFinished();
@@ -102,12 +137,78 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
   // process pending events
   QCoreApplication::processEvents();
 
-  delete module;
+  return signalTester.checkSignals(expectedSignals);
+}
+
+bool futureTestError(ctkCmdLineModule* module)
+{
+  qDebug() << "Testing ctkCmdLineModuleFuture error reporting.";
+
+  module->setValue("fileVar", "output1");
+  module->setValue("exitCodeVar", 24);
+  module->setValue("errorTextVar", "Some error occured\n");
+
+  QFutureWatcher watcher;
+  ctkCmdLineModuleFuture future = module->run();
+  watcher.setFuture(future);
+
+  try
+  {
+    future.waitForFinished();
+    return EXIT_FAILURE;
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    Q_ASSERT_X(e.errorCode() == 24, __FUNCTION__, "Error code mismatch");
+    Q_ASSERT_X(e.errorString() == "Some error occured\n", __FUNCTION__, "Error text mismatch");
+  }
+
+  // process pending events
+  QCoreApplication::processEvents();
+
+  return true;
+}
+
+int ctkCmdLineModuleFutureTest(int argc, char* argv[])
+{
+  QCoreApplication app(argc, argv);
+
+  ctkCmdLineModuleTestInstanceFactory factory;
+  ctkCmdLineModuleManager manager(&factory);
+
+  QString moduleFilename = app.applicationDirPath() + "/ctkCmdLineModuleTestBed";
+  ctkCmdLineModuleReference moduleRef = manager.registerModule(moduleFilename);
+  if (!moduleRef)
+  {
+    qCritical() << "Module at" << moduleFilename << "could not be registered";
+  }
+
+  QScopedPointer module(manager.createModule(moduleRef));
 
-  if (!signalTester.checkSignals(expectedSignals))
+  if (!futureTestStartFinish(module.data()))
   {
     return EXIT_FAILURE;
   }
 
+  if (!futureTestProgress(module.data()))
+  {
+    return EXIT_FAILURE;
+  }
+
+  if (!futureTestError(module.data()))
+  {
+    return EXIT_FAILURE;
+  }
+
+//  if (!futureTestPauseAndCancel(module.data()))
+//  {
+//    return EXIT_FAILURE;
+//  }
+
+  //  if (!futureTestResultReady(module.data()))
+  //  {
+  //    return EXIT_FAILURE;
+  //  }
+
   return EXIT_SUCCESS;
 }
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
index ead66cd575..93447c978b 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
@@ -33,24 +33,36 @@ void ctkCmdLineModuleSignalTester::moduleFinished()
   events.push_back("module.finished");
 }
 
-void ctkCmdLineModuleSignalTester::filterStarted(const QString &name, const QString &comment)
+void ctkCmdLineModuleSignalTester::moduleProgressValueChanged(int /*progress*/)
+{
+  events.push_back("module.progressValueChanged");
+}
+
+void ctkCmdLineModuleSignalTester::moduleProgressTextChanged(const QString &/*text*/)
+{
+  events.push_back("module.progressTextChanged");
+}
+
+void ctkCmdLineModuleSignalTester::filterStarted(const QString &/*name*/, const QString &/*comment*/)
 {
-  qDebug() << "Filter started:" << name << "(" << comment << ")";
   events.push_back("filter.started");
 }
 
-void ctkCmdLineModuleSignalTester::filterProgress(float progress)
+void ctkCmdLineModuleSignalTester::filterProgress(float /*progress*/)
 {
-  qDebug() << "progress:" << progress;
   events.push_back("filter.progress");
 }
 
-void ctkCmdLineModuleSignalTester::filterFinished(const QString &name)
+void ctkCmdLineModuleSignalTester::filterFinished(const QString &/*name*/)
 {
-  qDebug() << "Filter finished:" << name;
   events.push_back("filter.finished");
 }
 
+void ctkCmdLineModuleSignalTester::filterXmlError(const QString &/*error*/)
+{
+  events.push_back("filter.xmlError");
+}
+
 bool ctkCmdLineModuleSignalTester::checkSignals(const QList& expectedSignals)
 {
   if (events.size() != expectedSignals.size())
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
index 44d1cdb24b..82d764bb08 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
@@ -37,12 +37,15 @@ class ctkCmdLineModuleSignalTester : public QObject
 
 public Q_SLOTS:
 
-  void moduleStarted();
-  void moduleFinished();
-
-  void filterStarted(const QString& name, const QString& comment);
-  void filterProgress(float progress);
-  void filterFinished(const QString& name);
+  virtual void moduleStarted();
+  virtual void moduleFinished();
+  virtual void moduleProgressValueChanged(int progress);
+  virtual void moduleProgressTextChanged(const QString& text);
+
+  virtual void filterStarted(const QString& name, const QString& comment);
+  virtual void filterProgress(float progress);
+  virtual void filterFinished(const QString& name);
+  virtual void filterXmlError(const QString& error);
 
 private:
 
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp
index 42bf71915e..b1d3582b6b 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp
@@ -27,36 +27,193 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
+namespace {
 
-int ctkCmdLineModuleXmlProgressWatcherTest(int argc, char* argv[])
+// Custom signal tester
+class SignalTester : public ctkCmdLineModuleSignalTester
 {
-  QCoreApplication app(argc, argv);
+public:
 
-  QByteArray input;
-  QBuffer buffer(&input);
-  buffer.open(QIODevice::ReadWrite);
+  SignalTester() : accumulatedProgress(0)
+  {}
+
+  void filterStarted(const QString& name, const QString& comment)
+  {
+    ctkCmdLineModuleSignalTester::filterStarted(name, comment);
+    if (name != "My Filter")
+    {
+      error = "Filter name does not match \"My Filter\" (got \"" + name + "\")";
+      return;
+    }
+    if (comment != "Awesome filter")
+    {
+      error = "Filter comment does not match \"Awesome filter\" (got \"" + comment + "\")";
+      return;
+    }
+  }
+
+  void filterProgress(float progress)
+  {
+    ctkCmdLineModuleSignalTester::filterProgress(progress);
+    accumulatedProgress += progress;
+  }
+
+  void filterFinished(const QString& name)
+  {
+    ctkCmdLineModuleSignalTester::filterFinished(name);
+    if (name != "My Filter")
+    {
+      error = "Filter name does not match \"My Filter\" (got \"" + name + "\")";
+      return;
+    }
+  }
 
-  QByteArray ba = "My Filter"
-      "Awesome filter"
-      "0.3"
-      "0.6"
-      "0.9"
-      "My Filter23";
+  void filterXmlError(const QString& error)
+  {
+    ctkCmdLineModuleSignalTester::filterXmlError(error);
+    this->error = error;
+  }
 
+  QString error;
+  float accumulatedProgress;
+};
+
+bool xmlProgressWatcherTestSignalsAndValues()
+{
+  // Test data
+  QByteArray filterStart = "\n"
+                             "My Filter\n"
+                             "Awesome filter\n"
+                           "\n";
+  QString filterProgress = "%1\n";
+  QByteArray filterEnd = "\n"
+                           "My Filter\n"
+                           "23\n"
+                         "";
+
+  QBuffer buffer;
+  buffer.open(QIODevice::ReadWrite);
   ctkCmdLineModuleXmlProgressWatcher progressWatcher(&buffer);
 
-  ctkCmdLineModuleSignalTester signalTester;
+  SignalTester signalTester;
   signalTester.connect(&progressWatcher, SIGNAL(filterStarted(QString,QString)), &signalTester, SLOT(filterStarted(QString,QString)));
   signalTester.connect(&progressWatcher, SIGNAL(filterProgress(float)), &signalTester, SLOT(filterProgress(float)));
   signalTester.connect(&progressWatcher, SIGNAL(filterFinished(QString)), &signalTester, SLOT(filterFinished(QString)));
+  signalTester.connect(&progressWatcher, SIGNAL(filterXmlError(QString)), &signalTester, SLOT(filterXmlError(QString)));
+
+  buffer.write(filterStart);
+  QCoreApplication::processEvents();
+  buffer.write(filterProgress.arg(0.3).toLatin1());
+  QCoreApplication::processEvents();
+  buffer.write(filterProgress.arg(0.6).toLatin1());
+  QCoreApplication::processEvents();
+  buffer.write(filterProgress.arg(0.9).toLatin1());
+  QCoreApplication::processEvents();
+  buffer.write(filterEnd);
+  QCoreApplication::processEvents();
+
+  QList expectedSignals;
+  expectedSignals << "filter.started";
+  expectedSignals << "filter.progress";
+  expectedSignals << "filter.progress";
+  expectedSignals << "filter.progress";
+  expectedSignals << "filter.finished";
+
+  if (!signalTester.error.isEmpty())
+  {
+    qDebug() << signalTester.error;
+    return false;
+  }
+
+  if (!signalTester.checkSignals(expectedSignals))
+  {
+    return false;
+  }
+
+  if (signalTester.accumulatedProgress != 1.8f)
+  {
+    qDebug() << "Progress information wrong. Expected 1.8, got" << signalTester.accumulatedProgress;
+    return false;
+  }
+
+  return true;
+}
+
+bool xmlProgressWatcherTestMalformedXml()
+{
+  // Test data
+  QByteArray filterOutput = "\n"
+                              "My Filter\n"
+                              "Awesome filter\n"
+                              "chunk...\n"
+                              "0.2\n"
+                            "\n"
+                            "0.5\n"
+                            "\n"
+
+                              "My Filter\n"
+                              "23\n"
+                            "";
+
+  QBuffer buffer;
+  buffer.open(QIODevice::ReadWrite);
+  ctkCmdLineModuleXmlProgressWatcher progressWatcher(&buffer);
 
-  QDataStream xmlOut(&buffer);
-  xmlOut << ba;
+  SignalTester signalTester;
+  signalTester.connect(&progressWatcher, SIGNAL(filterStarted(QString,QString)), &signalTester, SLOT(filterStarted(QString,QString)));
+  signalTester.connect(&progressWatcher, SIGNAL(filterProgress(float)), &signalTester, SLOT(filterProgress(float)));
+  signalTester.connect(&progressWatcher, SIGNAL(filterFinished(QString)), &signalTester, SLOT(filterFinished(QString)));
+  signalTester.connect(&progressWatcher, SIGNAL(filterXmlError(QString)), &signalTester, SLOT(filterXmlError(QString)));
 
+  buffer.write(filterOutput);
   QCoreApplication::processEvents();
 
+
+  QList expectedSignals;
+  expectedSignals << "filter.xmlError";
+  expectedSignals << "filter.started";
+  expectedSignals << "filter.progress";
+  expectedSignals << "filter.finished";
+
+  if (!signalTester.error.isEmpty())
+  {
+    qDebug() << signalTester.error;
+    //return false;
+  }
+
+  if (!signalTester.checkSignals(expectedSignals))
+  {
+    return false;
+  }
+
+  if (signalTester.accumulatedProgress != 0.5f)
+  {
+    qDebug() << "Progress information wrong. Expected 1.8, got" << signalTester.accumulatedProgress;
+    return false;
+  }
+
+  return true;
+}
+
+}
+
+int ctkCmdLineModuleXmlProgressWatcherTest(int argc, char* argv[])
+{
+  QCoreApplication app(argc, argv);
+
+  if (!xmlProgressWatcherTestSignalsAndValues())
+  {
+    return EXIT_FAILURE;
+  }
+
+  if (!xmlProgressWatcherTestMalformedXml())
+  {
+    return EXIT_FAILURE;
+  }
+
   return EXIT_SUCCESS;
 }
diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
index 67ba86d41a..03fdd86f1d 100644
--- a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
@@ -46,6 +46,7 @@ int main(int argc, char* argv[])
   parser.addArgument("xml", "", QVariant::Bool, "Print a XML description of this modules command line interface");
   parser.addArgument("runtime", "", QVariant::Int, "Runtime in seconds", 1);
   parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0);
+  parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false);
   parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0);
   parser.addArgument("errorText", "", QVariant::String, "Error text (will not be printed on exit code 0)");
   QTextStream out(stdout, QIODevice::WriteOnly);
@@ -85,6 +86,7 @@ int main(int argc, char* argv[])
   float exitTime = parsedArgs["exitTime"].toFloat();
   int exitTimeMillis = static_cast(exitTime/2.0 * 1000.0);
   int exitCode = parsedArgs["exitCode"].toInt();
+  bool exitCrash = parsedArgs["exitCrash"].toBool();
   QString errorText = parsedArgs["errorText"].toString();
 
   QStringList outputs = parser.unparsedArguments();
@@ -92,6 +94,11 @@ int main(int argc, char* argv[])
   if (outputs.empty())
   {
     // no outputs given, just return
+    if (exitCrash)
+    {
+      int* crash = 0;
+      *crash = 5;
+    }
     if (exitCode != 0)
     {
       err << errorText;
@@ -106,11 +113,24 @@ int main(int argc, char* argv[])
 
   struct timespec nanostep;
 
-  foreach(QString output, outputs)
+  out << "\n";
+  out << "Test Filter\n";
+  out << "Does nothing useful\n";
+  out << "\n";
+
+  float progressStep = 1.0f / static_cast(outputs.size());
+  for(int i = 0; i < outputs.size(); ++i)
   {
+    QString output = outputs[i];
+
     if (exitTimeMillis != 0 && exitTimeMillis < time.elapsed())
     {
-      if (exitCode != 0)
+      if (exitCrash)
+      {
+        int* crash = 0;
+        *crash = 5;
+      }
+      if (exitCode != 0 && !errorText.isEmpty())
       {
         err << errorText;
       }
@@ -125,7 +145,22 @@ int main(int argc, char* argv[])
 
     // print the first output
     out << output; endl(out);
+
+    // report progress
+    out << "" << (i+1)*progressStep << "\n";
   }
 
-  return EXIT_SUCCESS;
+  // sleep 1 second to avoid squashing the last progress event with the finished event
+  sleep(1);
+
+  if (exitCrash)
+  {
+    int* crash = 0;
+    *crash = 5;
+  }
+  if (exitCode != 0 && !errorText.isEmpty())
+  {
+    err << errorText;
+  }
+  return exitCode;
 }
diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
index e1739cfdfe..a21060693a 100644
--- a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
+++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
@@ -46,6 +46,13 @@ Configurable behaviour for testing purposes.
       
       0
     
+    
+      exitCrashVar
+      exitCrash
+      Exit by crashing.
+      
+      false
+    
     
       errorTextVar
       errorText
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
index 21ddb473d2..a8dbbe8f2d 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
@@ -25,12 +25,12 @@
 #include "ctkCmdLineModuleParameterGroup.h"
 #include "ctkCmdLineModuleReference.h"
 #include "ctkCmdLineModuleProcessTask.h"
+#include "ctkCmdLineModuleFuture.h"
 
 #include "ctkException.h"
 
 #include 
 #include 
-#include 
 #include 
 
 struct ctkCmdLineModulePrivate
@@ -119,12 +119,18 @@ QStringList ctkCmdLineModule::commandLineArguments() const
       {
         argFlag = QString("--") + d->normalizeFlag(parameter.longFlag());
       }
-
       QStringList args;
       if (parameter.multiple())
       {
         args = valuesIter.value().toString().split(',', QString::SkipEmptyParts);
       }
+      else if (parameter.tag() == "boolean")
+      {
+        if (valuesIter.value().toBool())
+        {
+          cmdLineArgs << argFlag;
+        }
+      }
       else
       {
         args.push_back(valuesIter.value().toString());
@@ -147,7 +153,7 @@ QStringList ctkCmdLineModule::commandLineArguments() const
   return cmdLineArgs;
 }
 
-QFuture ctkCmdLineModule::run() const
+ctkCmdLineModuleFuture ctkCmdLineModule::run() const
 {
   QStringList args = commandLineArguments();
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.h b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
index cda0070b80..65c516da8c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
@@ -29,6 +29,8 @@
 template class QHash;
 template class QFuture;
 
+class ctkCmdLineModuleResult;
+typedef QFuture ctkCmdLineModuleFuture;
 class ctkCmdLineModuleReference;
 class ctkCmdLineModulePrivate;
 
@@ -59,7 +61,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModule : public QObject
 
   QStringList commandLineArguments() const;
 
-  QFuture run() const;
+  ctkCmdLineModuleFuture run() const;
 
   Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value);
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
new file mode 100644
index 0000000000..b6f9fb3c16
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
@@ -0,0 +1,173 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  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
+
+  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 CTKCMDLINEMODULEFUTURE_H
+#define CTKCMDLINEMODULEFUTURE_H
+
+#include "ctkCmdLineModuleFutureInterface.h"
+
+#include 
+#include 
+#include 
+
+template 
+class QFutureWatcher;
+template <>
+class QFutureWatcher;
+
+/**
+ * QFuture specialization with two additional methods:
+ *
+ *   - bool canCancel()
+ *   - bool canPause()
+ */
+template<>
+class QFuture
+{
+public:
+
+  QFuture()
+    : d(QFutureInterface::canceledResult())
+  { }
+  explicit QFuture(QFutureInterface *p) // internal
+    : d(*p)
+  { }
+  QFuture(const QFuture &other)
+    : d(other.d)
+  { }
+  ~QFuture()
+  { }
+
+  inline QFuture &operator=(const QFuture &other);
+  bool operator==(const QFuture &other) const { return (d == other.d); }
+  bool operator!=(const QFuture &other) const { return (d != other.d); }
+
+  // additional methods
+  bool canCancel() const { return  d.canCancel(); }
+  bool canPause() const { return d.canPause(); }
+
+  void cancel() { d.cancel(); }
+  bool isCanceled() const { return d.isCanceled(); }
+
+  void setPaused(bool paused) { d.setPaused(paused); }
+  bool isPaused() const { return d.isPaused(); }
+  void pause() { setPaused(true); }
+  void resume() { setPaused(false); }
+  void togglePaused() { d.togglePaused(); }
+
+  bool isStarted() const { return d.isStarted(); }
+  bool isFinished() const { return d.isFinished(); }
+  bool isRunning() const { return d.isRunning(); }
+
+  int resultCount() const { return d.resultCount(); }
+  int progressValue() const { return d.progressValue(); }
+  int progressMinimum() const { return d.progressMinimum(); }
+  int progressMaximum() const { return d.progressMaximum(); }
+  QString progressText() const { return d.progressText(); }
+  void waitForFinished() { d.waitForFinished(); }
+
+  inline ctkCmdLineModuleResult result() const;
+  inline ctkCmdLineModuleResult resultAt(int index) const;
+  bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); }
+
+  operator ctkCmdLineModuleResult() const { return result(); }
+  QList results() const { return d.results(); }
+
+  class const_iterator
+  {
+  public:
+    typedef std::bidirectional_iterator_tag iterator_category;
+    typedef qptrdiff difference_type;
+    typedef ctkCmdLineModuleResult value_type;
+    typedef const ctkCmdLineModuleResult *pointer;
+    typedef const ctkCmdLineModuleResult &reference;
+
+    inline const_iterator() {}
+    inline const_iterator(QFuture const * const _future, int _index) : future(_future), index(_index) {}
+    inline const_iterator(const const_iterator &o) : future(o.future), index(o.index)  {}
+    inline const_iterator &operator=(const const_iterator &o)
+    { future = o.future; index = o.index; return *this; }
+    inline const ctkCmdLineModuleResult &operator*() const { return future->d.resultReference(index); }
+    inline const ctkCmdLineModuleResult *operator->() const { return future->d.resultPointer(index); }
+
+    inline bool operator!=(const const_iterator &other) const
+    {
+      if (index == -1 && other.index == -1) // comparing end != end?
+        return false;
+      if (other.index == -1)
+        return (future->isRunning() || (index < future->resultCount()));
+      return (index != other.index);
+    }
+
+    inline bool operator==(const const_iterator &o) const { return !operator!=(o); }
+    inline const_iterator &operator++() { ++index; return *this; }
+    inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; }
+    inline const_iterator &operator--() { --index; return *this; }
+    inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; }
+    inline const_iterator operator+(int j) const { return const_iterator(future, index + j); }
+    inline const_iterator operator-(int j) const { return const_iterator(future, index - j); }
+    inline const_iterator &operator+=(int j) { index += j; return *this; }
+    inline const_iterator &operator-=(int j) { index -= j; return *this; }
+  private:
+    QFuture const * future;
+    int index;
+  };
+  friend class const_iterator;
+  typedef const_iterator ConstIterator;
+
+  const_iterator begin() const { return  const_iterator(this, 0); }
+  const_iterator constBegin() const { return  const_iterator(this, 0); }
+  const_iterator end() const { return const_iterator(this, -1); }
+  const_iterator constEnd() const { return const_iterator(this, -1); }
+
+private:
+  friend class QFutureWatcher;
+
+public: // Warning: the d pointer is not documented and is considered private.
+  mutable QFutureInterface d;
+};
+
+typedef QFuture ctkCmdLineModuleFuture;
+
+inline ctkCmdLineModuleFuture& ctkCmdLineModuleFuture::operator=(const ctkCmdLineModuleFuture& other)
+{
+  d = other.d;
+  return *this;
+}
+
+inline ctkCmdLineModuleResult ctkCmdLineModuleFuture::result() const
+{
+  d.waitForResult(0);
+  return d.resultReference(0);
+}
+
+inline ctkCmdLineModuleResult ctkCmdLineModuleFuture::resultAt(int index) const
+{
+  d.waitForResult(index);
+  return d.resultReference(index);
+}
+
+inline ctkCmdLineModuleFuture ctkCmdLineModuleFutureInterface::future()
+{
+  return ctkCmdLineModuleFuture(this);
+}
+
+#endif // CTKCMDLINEMODULEFUTURE_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
new file mode 100644
index 0000000000..1ab8af8f1e
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
@@ -0,0 +1,176 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  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
+
+  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 CTKCMDLINEMODULEFUTUREINTERFACE_H
+#define CTKCMDLINEMODULEFUTUREINTERFACE_H
+
+#include "ctkCmdLineModuleResult.h"
+
+#include 
+
+typedef QFuture ctkCmdLineModuleFuture;
+
+template <>
+class QFutureInterface : public QFutureInterfaceBase
+{
+
+public:
+
+  QFutureInterface(State initialState = NoState)
+    : QFutureInterfaceBase(initialState),
+      CanCancel(false), CanPause(false)
+  { }
+
+  QFutureInterface(const QFutureInterface &other)
+    : QFutureInterfaceBase(other),
+      CanCancel(false), CanPause(false)
+  { }
+
+  ~QFutureInterface()
+  {
+    if (referenceCountIsOne())
+      resultStore().clear();
+  }
+
+  static QFutureInterface canceledResult()
+  { return QFutureInterface(State(Started | Finished | Canceled)); }
+
+  QFutureInterface& operator=(const QFutureInterface& other)
+  {
+    if (referenceCountIsOne())
+      resultStore().clear();
+    QFutureInterfaceBase::operator=(other);
+    return *this;
+  }
+
+  inline ctkCmdLineModuleFuture future(); // implemented in ctkCmdLineModuleFuture.h
+
+  inline bool canCancel() const { return CanCancel; }
+  inline void setCanCancel(bool canCancel) { CanCancel = canCancel; }
+  inline bool canPause() const { return CanPause; }
+  inline void setCanPause(bool canPause) { CanPause = canPause; }
+
+  inline void reportResult(const ctkCmdLineModuleResult *result, int index = -1);
+  inline void reportResult(const ctkCmdLineModuleResult &result, int index = -1);
+  inline void reportResults(const QVector &results, int beginIndex = -1, int count = -1);
+  inline void reportFinished(const ctkCmdLineModuleResult *result = 0);
+
+  inline const ctkCmdLineModuleResult &resultReference(int index) const;
+  inline const ctkCmdLineModuleResult *resultPointer(int index) const;
+  inline QList results();
+
+private:
+
+  QtConcurrent::ResultStore &resultStore()
+  { return static_cast &>(resultStoreBase()); }
+  const QtConcurrent::ResultStore &resultStore() const
+  { return static_cast &>(resultStoreBase()); }
+
+  bool CanCancel;
+  bool CanPause;
+};
+
+inline void QFutureInterface::reportResult(const ctkCmdLineModuleResult *result, int index)
+{
+    QMutexLocker locker(mutex());
+    if (this->queryState(Canceled) || this->queryState(Finished)) {
+        return;
+    }
+
+    QtConcurrent::ResultStore &store = resultStore();
+
+
+    if (store.filterMode()) {
+        const int resultCountBefore = store.count();
+        store.addResult(index, result);
+        this->reportResultsReady(resultCountBefore, resultCountBefore + store.count());
+    } else {
+        const int insertIndex = store.addResult(index, result);
+        this->reportResultsReady(insertIndex, insertIndex + 1);
+    }
+}
+
+inline void QFutureInterface::reportResult(const ctkCmdLineModuleResult &result, int index)
+{
+    reportResult(&result, index);
+}
+
+inline void QFutureInterface::reportResults(const QVector &_results, int beginIndex, int count)
+{
+    QMutexLocker locker(mutex());
+    if (this->queryState(Canceled) || this->queryState(Finished)) {
+        return;
+    }
+
+    QtConcurrent::ResultStore &store = resultStore();
+
+    if (store.filterMode()) {
+        const int resultCountBefore = store.count();
+        store.addResults(beginIndex, &_results, count);
+        this->reportResultsReady(resultCountBefore, store.count());
+    } else {
+        const int insertIndex = store.addResults(beginIndex, &_results, count);
+        this->reportResultsReady(insertIndex, insertIndex + _results.count());
+    }
+}
+
+inline void QFutureInterface::reportFinished(const ctkCmdLineModuleResult *result)
+{
+    if (result)
+        reportResult(result);
+    QFutureInterfaceBase::reportFinished();
+}
+
+inline const ctkCmdLineModuleResult &QFutureInterface::resultReference(int index) const
+{
+    QMutexLocker lock(mutex());
+    return resultStore().resultAt(index).value();
+}
+
+inline const ctkCmdLineModuleResult *QFutureInterface::resultPointer(int index) const
+{
+    QMutexLocker lock(mutex());
+    return resultStore().resultAt(index).pointer();
+}
+
+inline QList QFutureInterface::results()
+{
+    if (this->isCanceled()) {
+        exceptionStore().throwPossibleException();
+        return QList();
+    }
+    QFutureInterfaceBase::waitForResult(-1);
+
+    QList res;
+    QMutexLocker lock(mutex());
+
+    QtConcurrent::ResultIterator it = resultStore().begin();
+    while (it != resultStore().end()) {
+        res.append(it.value());
+        ++it;
+    }
+
+    return res;
+}
+
+typedef QFutureInterface ctkCmdLineModuleFutureInterface;
+
+#endif // CTKCMDLINEMODULEFUTUREINTERFACE_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
index 6dfc8fd5ef..38d9adea46 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
@@ -21,28 +21,80 @@
 
 #include "ctkCmdLineModuleProcessTask.h"
 #include "ctkCmdLineModuleRunException.h"
+#include "ctkCmdLineModuleXmlProgressWatcher.h"
+#include "ctkCmdLineModuleFuture.h"
 
 #include 
 #include 
 #include 
 #include 
-#include 
 
+ctkCmdLineModuleProcessProgressWatcher::ctkCmdLineModuleProcessProgressWatcher(QProcess& process, const QString& location,
+                                                                               ctkCmdLineModuleFutureInterface &futureInterface)
+  : process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process),
+    progressValue(0)
+{
+  futureInterface.setProgressRange(0, 1000);
+
+  connect(&processXmlWatcher, SIGNAL(filterStarted(QString,QString)), SLOT(filterStarted(QString,QString)));
+  connect(&processXmlWatcher, SIGNAL(filterProgress(float)), SLOT(filterProgress(float)));
+  connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString)));
+  connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString)));
+}
+
+void ctkCmdLineModuleProcessProgressWatcher::filterStarted(const QString& name, const QString& comment)
+{
+  Q_UNUSED(comment)
+  futureInterface.setProgressValueAndText(incrementProgress(), name);
+}
+
+void ctkCmdLineModuleProcessProgressWatcher::filterProgress(float progress)
+{
+  futureInterface.setProgressValue(updateProgress(progress));
+}
+
+void ctkCmdLineModuleProcessProgressWatcher::filterFinished(const QString& name)
+{
+  futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name);
+}
+
+void ctkCmdLineModuleProcessProgressWatcher::filterXmlError(const QString &error)
+{
+  qDebug().nospace() << "[Module " << location << "]: " << error;
+}
+
+int ctkCmdLineModuleProcessProgressWatcher::updateProgress(float progress)
+{
+  progressValue = static_cast(progress * 1000.0f);
+  // normalize the value to lie between 0 and 1000.
+  // 0 is reported when the process starts and 1000 is reserved for
+  // reporting completion + standard output text
+  if (progressValue < 1) progressValue = 1;
+  if (progressValue > 999) progressValue = 999;
+  return progressValue;
+}
+
+int ctkCmdLineModuleProcessProgressWatcher::incrementProgress()
+{
+  if (++progressValue > 999) progressValue = 999;
+  return progressValue;
+}
 
 ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
   : location(location), args(args)
 {
+  this->setCanCancel(true);
 }
 
 ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask()
 {
 }
 
-QFuture ctkCmdLineModuleProcessTask::start()
+ctkCmdLineModuleFuture ctkCmdLineModuleProcessTask::start()
 {
   this->setRunnable(this);
   this->reportStarted();
-  QFuture future = this->future();
+  ctkCmdLineModuleFuture future = this->future();
   QThreadPool::globalInstance()->start(this, /*m_priority*/ 0);
   return future;
 }
@@ -56,39 +108,31 @@ void ctkCmdLineModuleProcessTask::run()
   }
 
   QProcess process;
+  process.setReadChannel(QProcess::StandardOutput);
+
   QEventLoop localLoop;
-  connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
-  connect(&process, SIGNAL(error(QProcess::ProcessError)), SLOT(error(QProcess::ProcessError)));
-  connect(&process, SIGNAL(readyReadStandardError()), SLOT(readyReadStandardError()));
-  connect(&process, SIGNAL(readyReadStandardOutput()), SLOT(readyReadStandardOutput()));
+  QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
+  QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
 
   process.start(location, args);
 
+  ctkCmdLineModuleProcessProgressWatcher progressWatcher(process, location, *this);
+  Q_UNUSED(progressWatcher)
+
   localLoop.exec();
 
-  if (process.exitCode() != 0 || process.exitStatus() == QProcess::CrashExit)
+  if (process.error() != QProcess::UnknownError)
+  {
+    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString()));
+  }
+  else if (process.exitCode() != 0)
   {
-    QString msg = "The process running \"%1\" ";
-    msg += process.exitStatus() == QProcess::CrashExit ? QString("crashed: ")
-                                                     : QString("exited with code %1: ").arg(process.exitCode());
-    msg += process.readAllStandardError();
-    this->reportException(ctkCmdLineModuleRunException(msg));
+    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.readAllStandardError()));
   }
 
-  this->setProgressValueAndText(100, process.readAllStandardOutput());
+  this->setProgressValueAndText(1000, process.readAllStandardError());
 
   //this->reportResult(result);
   this->reportFinished();
-}
-
-void ctkCmdLineModuleProcessTask::error(QProcess::ProcessError error)
-{
-}
 
-void ctkCmdLineModuleProcessTask::readyReadStandardError()
-{
-}
-
-void ctkCmdLineModuleProcessTask::readyReadStandardOutput()
-{
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
index 94466d436a..1e4dd8c252 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
@@ -22,37 +22,62 @@
 #ifndef CTKCMDLINEMODULEPROCESSTASK_H
 #define CTKCMDLINEMODULEPROCESSTASK_H
 
-#include 
+#include "ctkCmdLineModuleXmlProgressWatcher.h"
+#include "ctkCmdLineModuleFutureInterface.h"
 
 #include 
 #include 
 #include 
-#include 
+#include 
 
-class ctkCmdLineModuleProcessTask : public QObject, public QFutureInterface, public QRunnable
+class QProcess;
+
+class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable
 {
-  Q_OBJECT
 
 public:
 
   ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args);
   ~ctkCmdLineModuleProcessTask();
 
-  QFuture start();
+  ctkCmdLineModuleFuture start();
 
   void run();
 
+private:
+
+  const QString location;
+  const QStringList args;
+
+};
+
+class ctkCmdLineModuleProcessProgressWatcher : public QObject
+{
+  Q_OBJECT
+
+public:
+
+  ctkCmdLineModuleProcessProgressWatcher(QProcess& process, const QString& location,
+                                         ctkCmdLineModuleFutureInterface& futureInterface);
+
 protected Q_SLOTS:
 
-  void error(QProcess::ProcessError error);
-  void readyReadStandardError();
-  void readyReadStandardOutput();
+  void filterStarted(const QString& name, const QString& comment);
+  void filterProgress(float progress);
+  void filterFinished(const QString& name);
+
+  void filterXmlError(const QString& error);
 
 private:
 
-  const QString location;
-  const QStringList args;
-  QString result;
+  int updateProgress(float progress);
+  int incrementProgress();
+
+  QProcess& process;
+  QString location;
+  ctkCmdLineModuleFutureInterface& futureInterface;
+  ctkCmdLineModuleXmlProgressWatcher processXmlWatcher;
+  int progressValue;
 };
 
 #endif // CTKCMDLINEMODULEPROCESSTASK_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h
new file mode 100644
index 0000000000..be49256650
--- /dev/null
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h
@@ -0,0 +1,47 @@
+/*=============================================================================
+
+  Library: CTK
+
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+
+  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
+
+  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 CTKCMDLINEMODULERESULT_H
+#define CTKCMDLINEMODULERESULT_H
+
+#include 
+#include 
+
+class ctkCmdLineModuleResult
+{
+public:
+
+  ctkCmdLineModuleResult() {}
+
+  ctkCmdLineModuleResult(const QString& parameter, const QVariant& value)
+    : Parameter(parameter), Value(value)
+  {}
+
+  inline QString parameter() const { return Parameter; }
+  inline QVariant value() const { return Value; }
+
+private:
+
+  QString Parameter;
+  QVariant Value;
+};
+
+#endif // CTKCMDLINEMODULERESULT_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp
index 125c7b67e1..b41964c8ab 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp
@@ -16,18 +16,25 @@ See LICENSE.txt or http://www.mitk.org for details.
 
 #include "ctkCmdLineModuleRunException.h"
 
-ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg)
-  : QtConcurrent::Exception(), ctkException(msg)
+ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(
+    const QString& location, int errorCode, const QString &errorString)
+  : QtConcurrent::Exception(),
+    ctkException(QString("Running module \"%1\" failed with code %2: %3").arg(location).arg(errorCode).arg(errorString)),
+    Location(location), ErrorCode(errorCode), ErrorString(errorString)
 {
 }
 
-ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause)
-  : QtConcurrent::Exception(), ctkException(msg, cause)
+ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(
+    const QString& location, int errorCode, const QString &errorString,
+    const ctkCmdLineModuleRunException& cause)
+  : QtConcurrent::Exception(), ctkException(location, cause),
+    Location(location), ErrorCode(errorCode), ErrorString(errorString)
 {
 }
 
 ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o)
-  : QtConcurrent::Exception(o), ctkException(o)
+  : QtConcurrent::Exception(o), ctkException(o),
+    Location(o.Location), ErrorCode(o.ErrorCode), ErrorString(o.ErrorString)
 {
 }
 
@@ -35,6 +42,21 @@ ctkCmdLineModuleRunException::~ctkCmdLineModuleRunException() throw()
 {
 }
 
+QString ctkCmdLineModuleRunException::location() const throw()
+{
+  return Location;
+}
+
+int ctkCmdLineModuleRunException::errorCode() const throw()
+{
+  return ErrorCode;
+}
+
+QString ctkCmdLineModuleRunException::errorString() const throw()
+{
+  return ErrorString;
+}
+
 const char* ctkCmdLineModuleRunException::name() const throw()
 {
   return "CTK CommandLineModule Run Exception";
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h
index b15490853e..4e8e68ab4c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h
@@ -17,23 +17,32 @@ See LICENSE.txt or http://www.mitk.org for details.
 #ifndef CTKCMDLINEMODULERUNEXCEPTION_H
 #define CTKCMDLINEMODULERUNEXCEPTION_H
 
+#include "ctkCommandLineModulesCoreExport.h"
+
 #include 
 
 #include 
 
-class ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkException
+class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleRunException
+    : public QtConcurrent::Exception, public ctkException
 {
 public:
 
-  explicit ctkCmdLineModuleRunException(const QString& msg);
+  explicit ctkCmdLineModuleRunException(const QString& location, int errorCode,
+                                        const QString& errorString);
 
-  ctkCmdLineModuleRunException(const QString& msg, const ctkCmdLineModuleRunException& cause);
+  ctkCmdLineModuleRunException(const QString& location, int errorCode,
+                               const QString& errorString, const ctkCmdLineModuleRunException& cause);
   ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o);
 
   ctkCmdLineModuleRunException& operator=(const ctkCmdLineModuleRunException& o);
 
   ~ctkCmdLineModuleRunException() throw();
 
+  QString location() const throw();
+  int errorCode() const throw();
+  QString errorString() const throw();
+
   virtual const char* name() const throw();
   virtual const char* className() const throw();
   virtual ctkCmdLineModuleRunException* clone() const;
@@ -41,6 +50,12 @@ class ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkE
 
   virtual void raise() const;
 
+private:
+
+  QString Location;
+  int ErrorCode;
+  QString ErrorString;
+
 };
 
 #endif // CTKCMDLINEMODULERUNEXCEPTION_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp
index d59693738e..f711f1ad71 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp
@@ -36,15 +36,18 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate
 public:
 
   ctkCmdLineModuleXmlProgressWatcherPrivate(QIODevice* input, ctkCmdLineModuleXmlProgressWatcher* qq)
-    : input(input), q(qq), error(false)
-  {}
+    : input(input), readPos(0), q(qq), error(false), currentProgress(0)
+  {
+    // wrap the content in an artifical root element
+    reader.addData("");
+  }
 
   void _q_readyRead()
   {
-    QByteArray ba = input->readAll();
-    qDebug() << input->pos() << " [" << input->bytesAvailable() << "]:" << ba;
-    //reader.addData(ba);
-    //parseProgressXml();
+    input->seek(readPos);
+    reader.addData(input->readAll());
+    readPos = input->pos();
+    parseProgressXml();
   }
 
   void parseProgressXml()
@@ -55,92 +58,123 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate
       switch(type)
       {
       case QXmlStreamReader::NoToken: break;
-      case QXmlStreamReader::StartElement:
+      case QXmlStreamReader::Characters:
       {
-        QStringRef name = reader.name();
-        if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0)
-        {
-          stack.push_back(FILTER_START);
-          currentName.clear();
-          currentComment.clear();
-        }
-        else if (name.compare(FILTER_NAME, Qt::CaseInsensitive) == 0)
+        if (stack.empty()) break;
+
+        if (stack.size() == 2 && stack.front() == FILTER_START)
         {
-          if (stack.back() == FILTER_START || stack.back() == FILTER_END)
+          if (stack.back() == FILTER_NAME)
           {
-            currentName = reader.name().toString().trimmed();
+            currentName = reader.text().toString().trimmed();
           }
-        }
-        else if (name.compare(FILTER_COMMENT, Qt::CaseInsensitive) == 0)
-        {
-          if (stack.back() == FILTER_START)
+          else if (stack.back() == FILTER_COMMENT)
           {
-            currentComment = reader.name().toString().trimmed();
+            currentComment = reader.text().toString().trimmed();
           }
         }
-        else if (name.compare(FILTER_PROGRESS, Qt::CaseInsensitive) == 0)
+        else if (stack.size() == 1 && stack.back() == FILTER_PROGRESS)
+        {
+          currentProgress = reader.text().toString().toFloat();
+        }
+        break;
+      }
+      case QXmlStreamReader::StartElement:
+      {
+        QStringRef name = reader.name();
+        QString parent;
+        if (!stack.empty()) parent = stack.back();
+
+        if (name.compare("module-root") != 0)
         {
-          if (!stack.empty())
+          stack.push_back(name.toString());
+        }
+
+        if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0 ||
+            name.compare(FILTER_PROGRESS, Qt::CaseInsensitive) == 0 ||
+            name.compare(FILTER_END, Qt::CaseInsensitive) == 0)
+        {
+          if (!parent.isEmpty())
+          {
+            unexpectedNestedElement(name.toString());
+            break;
+          }
+
+          if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0)
           {
-            if (!error)
-            {
-              emit q->filterXmlError(QString("\"%1\" must be a top-level element, found at line %2.")
-                                     .arg(FILTER_PROGRESS).arg(reader.lineNumber()));
-            }
-            continue;
+            currentName.clear();
+            currentComment.clear();
+            currentProgress = 0;
           }
-          emit q->filterProgress(reader.text().toString().toFloat());
         }
-        type = reader.readNext();
         break;
       }
       case QXmlStreamReader::EndElement:
       {
         QStringRef name = reader.name();
-        if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0)
+
+        QString curr;
+        QString parent;
+        if (!stack.empty())
         {
-          if (stack.back() != FILTER_START)
-          {
-            if (!error)
-            {
-              emit q->filterXmlError(QString("Unexpected end tag \"%1\" found at line %2.")
-                                     .arg(FILTER_END).arg(reader.lineNumber()));
-            }
-            continue;
-          }
+          curr = stack.back();
           stack.pop_back();
-          emit q->filterStarted(currentName, currentComment);
+          if (!stack.empty()) parent = stack.back();
         }
-        else if (name.compare(FILTER_END, Qt::CaseInsensitive) == 0)
+
+        if (parent.isEmpty())
         {
-          if (!stack.empty())
+          if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0)
           {
-            if (!error)
-            {
-              emit q->filterXmlError(QString("\"%1\" must be a top-level element, found at line %2.")
-                                     .arg(FILTER_PROGRESS).arg(reader.lineNumber()));
-            }
-            continue;
+            emit q->filterStarted(currentName, currentComment);
+          }
+          else if (name.compare(FILTER_PROGRESS, Qt::CaseInsensitive) == 0)
+          {
+            emit q->filterProgress(currentProgress);
+          }
+          else if (name.compare(FILTER_END, Qt::CaseInsensitive) == 0)
+          {
+            emit q->filterFinished(currentName);
           }
-          stack.pop_back();
-          emit q->filterFinished(currentName);
         }
-        type = reader.readNext();
         break;
       }
       default:
-        type = reader.readNext();
+        break;
+      }
+      type = reader.readNext();
+    }
+
+    if (type == QXmlStreamReader::Invalid && reader.error() != QXmlStreamReader::PrematureEndOfDocumentError)
+    {
+      if (!error)
+      {
+        error = true;
+        emit q->filterXmlError(QString("Error parsing XML at line %1, column %2: ")
+                               .arg(reader.lineNumber()).arg(reader.columnNumber()) + reader.errorString());
       }
     }
   }
 
+  void unexpectedNestedElement(const QString& element)
+  {
+    if (!error)
+    {
+      error = true;
+      emit q->filterXmlError(QString("\"%1\" must be a top-level element, found at line %2.")
+                             .arg(element).arg(reader.lineNumber()));
+    }
+  }
+
   QIODevice* input;
+  qint64 readPos;
   ctkCmdLineModuleXmlProgressWatcher* q;
   bool error;
   QXmlStreamReader reader;
   QList stack;
   QString currentName;
   QString currentComment;
+  float currentProgress;
 };
 
 ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice* input)
@@ -153,9 +187,6 @@ ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice
     input->open(QIODevice::ReadOnly);
   }
   connect(d->input, SIGNAL(readyRead()), SLOT(_q_readyRead()));
-
-  // start parsing
-  d->_q_readyRead();
 }
 
 ctkCmdLineModuleXmlProgressWatcher::~ctkCmdLineModuleXmlProgressWatcher()

From f4d9a93d1baa8727326773d7ff404f582eef71b5 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Mon, 23 Jul 2012 11:55:03 +0100
Subject: [PATCH 059/247] Fix ctkCLModuleExplorerMainWindow to match new
 QFuture API

---
 .../ctkCLModuleExplorerMainWindow.cpp         | 32 +++++++++++++------
 .../ctkCLModuleExplorerMainWindow.h           | 10 +++---
 2 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
index c597d21221..c6652b8585 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
@@ -25,16 +25,17 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
-#include 
 #include 
 
 ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::ctkCLModuleExplorerMainWindow),
-  moduleManager(new ctkCmdLineModuleFactoryQtGui())
+  moduleManager(new ctkCmdLineModuleFactoryQtGui()),
+  watcher(NULL)
 {
   ui->setupUi(this);
 }
@@ -77,7 +78,17 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   QStringList cmdLineArgs = module->commandLineArguments();
   qDebug() << cmdLineArgs;
 
-  QFuture future = module->run();
+  if (watcher != NULL)
+  {
+    delete watcher;
+  }
+  watcher = new QFutureWatcher();
+  QObject::connect(watcher, SIGNAL(started()), this, SLOT(moduleStarted()));
+  QObject::connect(watcher, SIGNAL(finished()), this, SLOT(moduleFinished()));
+
+  ctkCmdLineModuleFuture future = module->run();
+  watcher->setFuture(future);
+
   try
   {
     future.waitForFinished();
@@ -86,17 +97,18 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   {
     qDebug() << e.printStackTrace();
   }
-
 }
 
-void ctkCLModuleExplorerMainWindow::futureFinished()
+void ctkCLModuleExplorerMainWindow::moduleStarted()
 {
-  qDebug() << "*** Future finished";
+  qDebug() << "*** moduleStarted";
   //qDebug() << "stdout:" << futureWatcher.future().standardOutput();
   //qDebug() << "stderr:" << futureWatcher.future().standardError();
 }
 
-//ctkCmdLineModuleReference ctkCLModuleExplorerMainWindow::moduleReference(int tabIndex)
-//{
-//  return mapTabToModuleRef[tabIndex];
-//}
+void ctkCLModuleExplorerMainWindow::moduleFinished()
+{
+  qDebug() << "*** moduleFinished";
+  //qDebug() << "stdout:" << futureWatcher.future().standardOutput();
+  //qDebug() << "stderr:" << futureWatcher.future().standardError();
+}
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
index 8e32a4e9ab..7c88a2fcd3 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
@@ -24,10 +24,11 @@
 
 #include 
 #include 
-//#include 
+#include 
 
 #include 
 #include 
+#include 
 
 class ctkCmdLineModuleReference;
 
@@ -49,23 +50,22 @@ protected Q_SLOTS:
 
   void on_actionRun_triggered();
 
-  void futureFinished();
+  void moduleStarted();
+  void moduleFinished();
 
 protected:
 
   void addModuleTab(const ctkCmdLineModuleReference& moduleRef);
-
-  //ctkCmdLineModuleReference moduleReference(int tabIndex);
   
 private:
 
   Ui::ctkCLModuleExplorerMainWindow *ui;
 
   ctkCmdLineModuleManager moduleManager;
+  QFutureWatcher* watcher;
 
   QHash mapTabToModuleRef;
 
-  //ctkCmdLineModuleProcessFutureWatcher futureWatcher;
 };
 
 #endif // CTKCLIPLUGINEXPLORERMAINWINDOW_H

From b1f6b10bc4b83d38f1e5250d8e2a3b5cf46e47c9 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 11:19:15 -0400
Subject: [PATCH 060/247] Expose signal so users of app widget know about
 directory imports

Allows users of the widget to process the data after it
has been imported.
---
 Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp | 5 +++++
 Libs/DICOM/Widgets/ctkDICOMAppWidget.h   | 2 ++
 2 files changed, 7 insertions(+)

diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
index dbdc495c8c..87cfdef5e8 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
@@ -448,10 +448,15 @@ void ctkDICOMAppWidget::onImportDirectory(QString directory)
     connect(d->DICOMIndexer.data(), SIGNAL(progress(int)),
             this, SLOT(onProgress(int)));
 
+    // close the dialog
     connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
             progress, SLOT(close()));
+    // reset the database to show new data
     connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
             &d->DICOMModel, SLOT(reset()));
+    // allow users of this widget to know that the process has finished
+    connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
+            this, SIGNAL(directoryImported()));
 
     d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory);
   }
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
index 5598cc4054..8861efeb4b 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
@@ -70,6 +70,8 @@ public Q_SLOTS:
   void databaseDirectoryChanged(const QString&);
   /// Emited when query/retrieve operation has happened
   void queryRetrieveFinished();
+  /// Emited when the directory import operation has completed
+  void directoryImported();
 
 protected:
     QScopedPointer d_ptr;

From 199c83bd0676c311845bfa6459bd5848f178c0e1 Mon Sep 17 00:00:00 2001
From: Andras Lasso 
Date: Mon, 23 Jul 2012 11:05:09 -0400
Subject: [PATCH 061/247] Added Modality field to series table Added Series
 level Modality and SeriesNumber to the DICOM model

---
 Libs/DICOM/Core/Resources/dicom-sample.sql | 56 +++++++++++-----------
 Libs/DICOM/Core/Resources/dicom-schema.sql |  1 +
 Libs/DICOM/Core/ctkDICOMDatabase.cpp       | 18 +++----
 Libs/DICOM/Core/ctkDICOMModel.cpp          |  2 +-
 4 files changed, 40 insertions(+), 37 deletions(-)

diff --git a/Libs/DICOM/Core/Resources/dicom-sample.sql b/Libs/DICOM/Core/Resources/dicom-sample.sql
index 31190d7d13..376509a31e 100644
--- a/Libs/DICOM/Core/Resources/dicom-sample.sql
+++ b/Libs/DICOM/Core/Resources/dicom-sample.sql
@@ -2233,35 +2233,35 @@ CREATE TABLE 'Patients' (   'UID' INTEGER PRIMARY KEY AUTOINCREMENT,   'Patients
 INSERT INTO "Patients" VALUES(14,'Austrialian','8775070',20060101,10100,'M','A volunteer','35');
 INSERT INTO "Patients" VALUES(15,'09.11.24-14:36:24-STD','09.11.24-14:36:24-STD-4.0.4094797',18581118,'','O','','78');
 INSERT INTO "Patients" VALUES(16,'MROVERLAY-13','09.11.24-14:37:10-STD-1.3.12.2.1107.5.2.31.30287',19560304,'','O','','102');
-CREATE TABLE 'Series' (   'SeriesInstanceUID' VARCHAR(255) NOT NULL ,   'StudyInstanceUID' VARCHAR(45) NOT NULL ,   'SeriesNumber' INT NULL ,   'SeriesDate' DATE NULL ,   'SeriesTime' VARCHAR(20) NULL ,   'SeriesDescription' VARCHAR(255) NULL ,   'BodyPartExamined' VARCHAR(255) NULL ,   'FrameOfReferenceUID' VARCHAR(255) NULL ,   'AcquisitionNumber' INT NULL ,   'ContrastAgent' VARCHAR(255) NULL ,   'ScanningSequence' VARCHAR(45) NULL ,   'EchoNumber' INT NULL ,   'TemporalPosition' INT NULL ,   PRIMARY KEY ('SeriesInstanceUID') );
+CREATE TABLE 'Series' (   'SeriesInstanceUID' VARCHAR(255) NOT NULL ,   'StudyInstanceUID' VARCHAR(45) NOT NULL ,   'SeriesNumber' INT NULL ,   'SeriesDate' DATE NULL ,   'SeriesTime' VARCHAR(20) NULL ,   'SeriesDescription' VARCHAR(255) NULL ,   'Modality' VARCHAR(20) NULL ,   'BodyPartExamined' VARCHAR(255) NULL ,   'FrameOfReferenceUID' VARCHAR(255) NULL ,   'AcquisitionNumber' INT NULL ,   'ContrastAgent' VARCHAR(255) NULL ,   'ScanningSequence' VARCHAR(45) NULL ,   'EchoNumber' INT NULL ,   'TemporalPosition' INT NULL ,   PRIMARY KEY ('SeriesInstanceUID') );
 INSERT INTO "Series" VALUES('1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058','1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',123456,'','','None','','',0,'','',0,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173529.684000','DynaCT Nat Fill HU Normal [InSpace3D]','','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000394',1,'','',0,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173453.699000','Images for VOI selection','','',1,'','',0,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',17,'2009-11-24','160901.687000','t1_spc_WIP537_cor_body','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',18,'2009-11-24','161741.952000','t1_spc_WIP537_cor_surface','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',20,'2009-11-24','171701.952000','t1_spc_WIP537_cor_surface_PreScanNormalize_Needle','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',9,'2009-11-24','151607.280000','t1_se_ax_OFF_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',5,'2009-11-24','150154.798000','t2_spc_ns_sag_p2_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',6,'2009-11-24','150756.655000','t1_se_ax_OFF_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',19,'2009-11-24','163552.202000','t1_spc_WIP537_cor_surface_PreScanNormalize','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',16,'2009-11-24','154932.124000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',7,'2009-11-24','151226.577000','VIBE_1x1x1_body','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',4,'2009-11-24','145754.627000','VIBE_1x1x1_body','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',3,'2009-11-24','145630.752000','VIBE_1x1x1','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',8,'2009-11-24','151416.108000','t1_se_ax_OFF_iso_body','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',1,'2009-11-24','144410.799000','SCOUT','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',11,'2009-11-24','152020.233000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',12,'2009-11-24','152211.187000','t1_se_ax_OFF_2mm','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',15,'2009-11-24','154334.780000','SCOUT','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','GR',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',2,'2009-11-24','144806.174000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',10,'2009-11-24','151758.015000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',13,'2009-11-24','152401.983000','t1_se_ax_OFF_2mm_body','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',14,'2009-11-24','152554.999000','t1_se_ax_OFF_2mm','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',103,'2009-11-24','171811.576000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',102,'2009-11-24','163724.171000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',101,'2009-11-24','162255.999000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',99,'2009-11-24','170811.702000','PhoenixZIPReport','','',0,'','',0,0);
-INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',100,'2009-11-24','162146.108000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173529.684000','DynaCT Nat Fill HU Normal [InSpace3D]','CT','','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000394',1,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173453.699000','Images for VOI selection','CT','','',1,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',17,'2009-11-24','160901.687000','t1_spc_WIP537_cor_body','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',18,'2009-11-24','161741.952000','t1_spc_WIP537_cor_surface','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',20,'2009-11-24','171701.952000','t1_spc_WIP537_cor_surface_PreScanNormalize_Needle','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',9,'2009-11-24','151607.280000','t1_se_ax_OFF_iso','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',5,'2009-11-24','150154.798000','t2_spc_ns_sag_p2_iso','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',6,'2009-11-24','150756.655000','t1_se_ax_OFF_iso','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',19,'2009-11-24','163552.202000','t1_spc_WIP537_cor_surface_PreScanNormalize','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',16,'2009-11-24','154932.124000','t1_se_ax_OFF','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',7,'2009-11-24','151226.577000','VIBE_1x1x1_body','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',4,'2009-11-24','145754.627000','VIBE_1x1x1_body','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',3,'2009-11-24','145630.752000','VIBE_1x1x1','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',8,'2009-11-24','151416.108000','t1_se_ax_OFF_iso_body','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',1,'2009-11-24','144410.799000','SCOUT','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',11,'2009-11-24','152020.233000','t1_se_ax_OFF','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',12,'2009-11-24','152211.187000','t1_se_ax_OFF_2mm','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',15,'2009-11-24','154334.780000','SCOUT','MR','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',2,'2009-11-24','144806.174000','t1_se_ax_OFF','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',10,'2009-11-24','151758.015000','t1_se_ax_OFF','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',13,'2009-11-24','152401.983000','t1_se_ax_OFF_2mm_body','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',14,'2009-11-24','152554.999000','t1_se_ax_OFF_2mm','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',103,'2009-11-24','171811.576000','','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',102,'2009-11-24','163724.171000','','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',101,'2009-11-24','162255.999000','','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',99,'2009-11-24','170811.702000','PhoenixZIPReport','MR','','',0,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',100,'2009-11-24','162146.108000','','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
 CREATE TABLE 'Studies' (   'StudyInstanceUID' VARCHAR(255) NOT NULL ,   'PatientsUID' INT NOT NULL ,   'StudyID' VARCHAR(255) NULL ,   'StudyDate' DATE NULL ,   'StudyTime' VARCHAR(20) NULL ,   'AccessionNumber' VARCHAR(255) NULL ,   'ModalitiesInStudy' VARCHAR(255) NULL ,   'InstitutionName' VARCHAR(255) NULL , 'ReferringPhysician' VARCHAR(255) NULL ,  'PerformingPhysiciansName' VARCHAR(255) NULL , 'StudyDescription' VARCHAR(255) NULL ,  PRIMARY KEY ('StudyInstanceUID') );
 INSERT INTO "Studies" VALUES('1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',14,'123456','2009-01-02','010100.000000','1','','Hospital YYY', 'Unknown','me','None');
 INSERT INTO "Studies" VALUES('1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',15,'Default StudyID','2009-11-24','143624.000000','','','Hospital XXX', '','you','');
diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index 72a0d4f0e6..c8bdd9b92c 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -34,6 +34,7 @@ CREATE TABLE 'Series' (
   'SeriesDate' DATE NULL ,
   'SeriesTime' VARCHAR(20) NULL ,
   'SeriesDescription' VARCHAR(255) NULL ,
+  'Modality' VARCHAR(20) NULL ,
   'BodyPartExamined' VARCHAR(255) NULL ,
   'FrameOfReferenceUID' VARCHAR(64) NULL ,
   'AcquisitionNumber' INT NULL ,
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 634e56e724..249ce46f7d 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -783,6 +783,7 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS
       QString seriesDate(ctkDataset.GetElementAsString(DCM_SeriesDate) );
       QString seriesTime(ctkDataset.GetElementAsString(DCM_SeriesTime) );
       QString seriesDescription(ctkDataset.GetElementAsString(DCM_SeriesDescription) );
+      QString modality(ctkDataset.GetElementAsString(DCM_Modality) );
       QString bodyPartExamined(ctkDataset.GetElementAsString(DCM_BodyPartExamined) );
       QString frameOfReferenceUID(ctkDataset.GetElementAsString(DCM_FrameOfReferenceUID) );
       QString contrastAgent(ctkDataset.GetElementAsString(DCM_ContrastBolusAgent) );
@@ -793,20 +794,21 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS
       long temporalPosition(ctkDataset.GetElementAsInteger(DCM_TemporalPositionIdentifier) );
 
       QSqlQuery insertSeriesStatement ( Database );
-      insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
+      insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'Modality', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
       insertSeriesStatement.bindValue ( 0, seriesInstanceUID );
       insertSeriesStatement.bindValue ( 1, studyInstanceUID );
       insertSeriesStatement.bindValue ( 2, static_cast(seriesNumber) );
       insertSeriesStatement.bindValue ( 3, seriesDate );
       insertSeriesStatement.bindValue ( 4, QDate::fromString ( seriesTime, "yyyyMMdd" ) );
       insertSeriesStatement.bindValue ( 5, seriesDescription );
-      insertSeriesStatement.bindValue ( 6, bodyPartExamined );
-      insertSeriesStatement.bindValue ( 7, frameOfReferenceUID );
-      insertSeriesStatement.bindValue ( 8, static_cast(acquisitionNumber) );
-      insertSeriesStatement.bindValue ( 9, contrastAgent );
-      insertSeriesStatement.bindValue ( 10, scanningSequence );
-      insertSeriesStatement.bindValue ( 11, static_cast(echoNumber) );
-      insertSeriesStatement.bindValue ( 12, static_cast(temporalPosition) );
+      insertSeriesStatement.bindValue ( 6, modality );
+      insertSeriesStatement.bindValue ( 7, bodyPartExamined );
+      insertSeriesStatement.bindValue ( 8, frameOfReferenceUID );
+      insertSeriesStatement.bindValue ( 9, static_cast(acquisitionNumber) );
+      insertSeriesStatement.bindValue ( 10, contrastAgent );
+      insertSeriesStatement.bindValue ( 11, scanningSequence );
+      insertSeriesStatement.bindValue ( 12, static_cast(echoNumber) );
+      insertSeriesStatement.bindValue ( 13, static_cast(temporalPosition) );
       if ( !insertSeriesStatement.exec() )
         {
           logger.error ( "Error executing statament: "
diff --git a/Libs/DICOM/Core/ctkDICOMModel.cpp b/Libs/DICOM/Core/ctkDICOMModel.cpp
index bf8e0661a3..e94aa64771 100644
--- a/Libs/DICOM/Core/ctkDICOMModel.cpp
+++ b/Libs/DICOM/Core/ctkDICOMModel.cpp
@@ -344,7 +344,7 @@ void ctkDICOMModelPrivate::updateQueries(Node* node)const
         {
         condition.append("SeriesDescription LIKE \"%" + this->SearchParameters["Series"].toString() + "%\"" + " AND ");
         }
-      query = this->generateQuery("SeriesInstanceUID as UID, SeriesDescription as Name, BodyPartExamined as Scan, SeriesDate as Date, AcquisitionNumber as Number","Series",condition + QString("StudyInstanceUID='%1'").arg(node->UID));
+      query = this->generateQuery("SeriesInstanceUID as UID, SeriesDescription as Name, Modality as Age, SeriesNumber as Scan, BodyPartExamined as \"Subject ID\", SeriesDate as Date, AcquisitionNumber as Number","Series",condition + QString("StudyInstanceUID='%1'").arg(node->UID));
       logger.debug ( "ctkDICOMModelPrivate::updateQueries for Study: query is: " + query );
       break;
     case ctkDICOMModel::SeriesType:

From 7f586848d623eb9aed5d0699304c064a0fb645d8 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 11:36:40 -0400
Subject: [PATCH 062/247] Display "No description" rather than empty string in
 model view

(Thanks Andras Lasso!)
---
 Libs/DICOM/Core/ctkDICOMModel.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMModel.cpp b/Libs/DICOM/Core/ctkDICOMModel.cpp
index e94aa64771..59d640c99c 100644
--- a/Libs/DICOM/Core/ctkDICOMModel.cpp
+++ b/Libs/DICOM/Core/ctkDICOMModel.cpp
@@ -497,7 +497,16 @@ QVariant ctkDICOMModel::data ( const QModelIndex & dataIndex, int role ) const
     // invalid).
     return QString();
     }
-  return d->value(parentIndex, dataIndex.row(), field);
+
+  QVariant dataValue=d->value(parentIndex, dataIndex.row(), field);
+  if (dataValue.isNull())
+  {
+    if (columnName.compare("Name")==0)
+    {
+      return QString("No description");
+    }
+  }
+  return dataValue;
 }
 
 //------------------------------------------------------------------------------

From b8b35b40948522e53078536e9a928e65c924d112 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 12:29:05 -0400
Subject: [PATCH 063/247] Fix the insert statement to account for the extra
 modality field

---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 249ce46f7d..c2193d095b 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -794,7 +794,7 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS
       long temporalPosition(ctkDataset.GetElementAsInteger(DCM_TemporalPositionIdentifier) );
 
       QSqlQuery insertSeriesStatement ( Database );
-      insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'Modality', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
+      insertSeriesStatement.prepare ( "INSERT INTO Series ( 'SeriesInstanceUID', 'StudyInstanceUID', 'SeriesNumber', 'SeriesDate', 'SeriesTime', 'SeriesDescription', 'Modality', 'BodyPartExamined', 'FrameOfReferenceUID', 'AcquisitionNumber', 'ContrastAgent', 'ScanningSequence', 'EchoNumber', 'TemporalPosition' ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )" );
       insertSeriesStatement.bindValue ( 0, seriesInstanceUID );
       insertSeriesStatement.bindValue ( 1, studyInstanceUID );
       insertSeriesStatement.bindValue ( 2, static_cast(seriesNumber) );

From 571dfebf0a8d7c2d8dd6e039d6bac040432fae06 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Mon, 23 Jul 2012 17:34:14 +0100
Subject: [PATCH 064/247] Add slots for moduleProgressValueChanged
 moduleProgressTextChanged in ctkCLModuleExplorerMainWindow

---
 .../ctkCLModuleExplorerMainWindow.cpp            | 16 ++++++++++++----
 .../ctkCLModuleExplorerMainWindow.h              |  2 ++
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
index c6652b8585..7d1edb76f5 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
@@ -85,6 +85,8 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   watcher = new QFutureWatcher();
   QObject::connect(watcher, SIGNAL(started()), this, SLOT(moduleStarted()));
   QObject::connect(watcher, SIGNAL(finished()), this, SLOT(moduleFinished()));
+  QObject::connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(moduleProgressValueChanged(int)));
+  QObject::connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(moduleProgressTextChanged(QString)));
 
   ctkCmdLineModuleFuture future = module->run();
   watcher->setFuture(future);
@@ -102,13 +104,19 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
 void ctkCLModuleExplorerMainWindow::moduleStarted()
 {
   qDebug() << "*** moduleStarted";
-  //qDebug() << "stdout:" << futureWatcher.future().standardOutput();
-  //qDebug() << "stderr:" << futureWatcher.future().standardError();
 }
 
 void ctkCLModuleExplorerMainWindow::moduleFinished()
 {
   qDebug() << "*** moduleFinished";
-  //qDebug() << "stdout:" << futureWatcher.future().standardOutput();
-  //qDebug() << "stderr:" << futureWatcher.future().standardError();
+}
+
+void ctkCLModuleExplorerMainWindow::moduleProgressValueChanged(int value)
+{
+  qDebug() << "*** moduleProgressValueChanged int=" << value;
+}
+
+void ctkCLModuleExplorerMainWindow::moduleProgressTextChanged(QString value)
+{
+  qDebug() << "*** moduleProgressTextChanged QString=" << value;
 }
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
index 7c88a2fcd3..5d0f9856cd 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
@@ -52,6 +52,8 @@ protected Q_SLOTS:
 
   void moduleStarted();
   void moduleFinished();
+  void moduleProgressValueChanged(int);
+  void moduleProgressTextChanged(QString);
 
 protected:
 

From 6b014ec03aa7635bf7e2e5b23a6154bae99377bf Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 15:15:43 -0400
Subject: [PATCH 065/247] Add schema updating to ctkDICOM code

This is based on work by Marco Nolden to do an in-place update
of the database schema.

The new commits here provide a way to detect when a schema
update is needed using a new table in the database.

Also the schema update emits signals as the update goes on.

Also there is now a test and some examples of old schema so
we can verify things are working.

Also there is a uniform method to reset the effiency variables
so they don't accidentally result in missed entries after
removing data or updating the schema.

The app widget and ctkDICOM example application now support updating
the schema as neeed.
---
 .../DICOM/Core/Resources/dicom-old-schema.sql |   61 +
 .../Resources/dicom-sample-old-schema.sql     | 2276 +++++++++++++++++
 Libs/DICOM/Core/Resources/dicom-schema.sql    |    4 +
 Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt    |    4 +
 .../Testing/Cpp/ctkDICOMDatabaseTest3.cpp     |  114 +
 Libs/DICOM/Core/ctkDICOMDatabase.cpp          |   75 +-
 Libs/DICOM/Core/ctkDICOMDatabase.h            |   21 +-
 Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp      |   51 +
 Libs/DICOM/Widgets/ctkDICOMAppWidget.h        |    5 +
 9 files changed, 2603 insertions(+), 8 deletions(-)
 create mode 100644 Libs/DICOM/Core/Resources/dicom-old-schema.sql
 create mode 100644 Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql
 create mode 100644 Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest3.cpp

diff --git a/Libs/DICOM/Core/Resources/dicom-old-schema.sql b/Libs/DICOM/Core/Resources/dicom-old-schema.sql
new file mode 100644
index 0000000000..72a0d4f0e6
--- /dev/null
+++ b/Libs/DICOM/Core/Resources/dicom-old-schema.sql
@@ -0,0 +1,61 @@
+-- 
+-- A simple SQLITE3 database schema for modelling locally stored DICOM files 
+-- 
+-- Note: the semicolon at the end is necessary for the simple parser to separate
+--       the statements since the SQlite driver does not handle multiple
+--       commands per QSqlQuery::exec call!
+-- ;
+
+DROP TABLE IF EXISTS 'Images' ;
+DROP TABLE IF EXISTS 'Patients' ;
+DROP TABLE IF EXISTS 'Series' ;
+DROP TABLE IF EXISTS 'Studies' ;
+DROP TABLE IF EXISTS 'Directories' ;
+
+CREATE TABLE 'Images' (
+  'SOPInstanceUID' VARCHAR(64) NOT NULL,
+  'Filename' VARCHAR(1024) NOT NULL ,
+  'SeriesInstanceUID' VARCHAR(64) NOT NULL ,
+  'InsertTimestamp' VARCHAR(20) NOT NULL ,
+  PRIMARY KEY ('SOPInstanceUID') );
+CREATE TABLE 'Patients' (
+  'UID' INTEGER PRIMARY KEY AUTOINCREMENT,
+  'PatientsName' VARCHAR(255) NULL ,
+  'PatientID' VARCHAR(255) NULL ,
+  'PatientsBirthDate' DATE NULL ,
+  'PatientsBirthTime' TIME NULL ,
+  'PatientsSex' varchar(1) NULL ,
+  'PatientsAge' varchar(10) NULL ,
+  'PatientsComments' VARCHAR(255) NULL );
+CREATE TABLE 'Series' (
+  'SeriesInstanceUID' VARCHAR(64) NOT NULL ,
+  'StudyInstanceUID' VARCHAR(64) NOT NULL ,
+  'SeriesNumber' INT NULL ,
+  'SeriesDate' DATE NULL ,
+  'SeriesTime' VARCHAR(20) NULL ,
+  'SeriesDescription' VARCHAR(255) NULL ,
+  'BodyPartExamined' VARCHAR(255) NULL ,
+  'FrameOfReferenceUID' VARCHAR(64) NULL ,
+  'AcquisitionNumber' INT NULL ,
+  'ContrastAgent' VARCHAR(255) NULL ,
+  'ScanningSequence' VARCHAR(45) NULL ,
+  'EchoNumber' INT NULL ,
+  'TemporalPosition' INT NULL ,
+  PRIMARY KEY ('SeriesInstanceUID') );
+CREATE TABLE 'Studies' (
+  'StudyInstanceUID' VARCHAR(64) NOT NULL ,
+  'PatientsUID' INT NOT NULL ,
+  'StudyID' VARCHAR(255) NULL ,
+  'StudyDate' DATE NULL ,
+  'StudyTime' VARCHAR(20) NULL ,
+  'AccessionNumber' VARCHAR(255) NULL ,
+  'ModalitiesInStudy' VARCHAR(255) NULL ,
+  'InstitutionName' VARCHAR(255) NULL ,
+  'ReferringPhysician' VARCHAR(255) NULL ,
+  'PerformingPhysiciansName' VARCHAR(255) NULL ,
+  'StudyDescription' VARCHAR(255) NULL ,
+  PRIMARY KEY ('StudyInstanceUID') );
+
+CREATE TABLE 'Directories' (
+  'Dirname' VARCHAR(1024) ,
+  PRIMARY KEY ('Dirname') );
diff --git a/Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql b/Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql
new file mode 100644
index 0000000000..31190d7d13
--- /dev/null
+++ b/Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql
@@ -0,0 +1,2276 @@
+--  
+-- initialize a small sample database from an empty database. 
+-- For the corresponding DICOM files and more information see
+-- http://www.slicer.org/slicerWiki/index.php/DICOM:Database
+-- 
+-- Note: the semicolon at the end is necessary for the simple parser to separate
+--       the statements since the SQlite driver does not handle multiple
+--       commands per QSqlQuery::exec call!
+-- ;
+ 
+BEGIN TRANSACTION;
+DROP TABLE IF EXISTS 'Images' ;
+DROP TABLE IF EXISTS 'Patients' ;
+DROP TABLE IF EXISTS 'Series' ;
+DROP TABLE IF EXISTS 'Studies' ;
+DROP TABLE IF EXISTS 'Directories' ;
+CREATE TABLE 'Images' (   'Filename' VARCHAR(1024) NOT NULL ,   'SeriesInstanceUID' VARCHAR(255) NOT NULL ,   PRIMARY KEY ('Filename') );
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead24.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead8.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead51.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead87.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead4.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead92.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead79.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead56.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead62.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead16.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead53.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead89.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead17.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead35.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead93.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead85.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead39.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead90.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead65.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead9.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead36.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead76.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead78.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead73.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead14.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead75.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead37.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead86.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead12.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead55.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead31.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead28.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead84.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead34.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead26.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead54.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead30.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead67.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead50.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead22.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead6.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead32.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead68.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead38.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead61.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead43.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead40.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead45.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead21.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead29.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead3.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead15.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead66.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead48.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead23.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead47.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead81.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead72.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead44.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead70.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead82.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead59.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead88.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead1.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead10.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead58.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead46.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead33.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead7.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead42.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead27.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead49.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead13.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead41.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead71.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead77.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead25.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead64.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead52.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead11.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead2.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead57.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead69.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead60.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead20.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead74.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead5.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead80.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead19.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead91.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead83.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead18.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CTHeadAxialDicom/CTHead63.dcm','1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118383','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119059','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117047','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118425','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116697','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119927','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119535','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119437','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117543','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105475','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117921','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116179','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118509','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119913','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117389','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118103','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117893','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105783','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105147','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105503','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119871','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116151','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119269','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118755','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117585','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116879','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117865','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115899','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115913','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105797','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105909','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118905','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116599','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119521','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118467','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105161','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115319','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118710','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105531','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116011','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119815','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117215','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105307','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117501','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116235','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116767','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116851','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116865','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115885','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116081','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117711','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118439','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116039','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115941','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119731','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116669','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105377','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116515','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118565','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117837','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105559','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118313','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116109','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115459','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117291','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119703','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118854','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105063','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116305','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116137','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118299','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117089','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115431','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118075','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116025','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118215','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115655','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119675','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119633','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119003','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118701','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105881','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118481','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118495','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115795','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118649','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105021','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116781','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118145','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118131','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116263','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105741','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119199','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118061','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119605','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105895','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115955','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115529','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117683','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115473','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116487','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116991','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118369','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117375','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105489','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117347','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117277','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117851','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117627','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118947','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119283','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116655','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105433','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116165','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118728','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119941','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115641','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116403','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118397','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117145','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119689','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118355','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118047','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117459','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117655','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118607','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115403','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118271','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118635','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105251','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119787','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116711','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115697','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119241','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118791','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105447','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116375','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115809','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115487','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118523','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105951','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117879','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117403','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119983','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119465','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119395','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115389','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119899','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116123','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105671','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116795','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116221','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105811','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119843','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115969','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115669','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116837','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119073','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119101','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105979','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117187','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119143','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105713','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117557','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115263','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117319','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115501','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119381','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119661','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117949','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115997','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118809','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116557','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117669','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115683','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118257','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117977','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117739','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116949','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119647','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115871','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118327','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118692','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116347','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116753','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117529','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119717','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105293','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116585','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118719','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117571','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119451','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105657','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117305','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119969','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117725','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105349','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116935','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115781','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118746','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119213','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118663','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105119','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117641','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105035','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117697','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118800','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115375','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118818','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105839','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115739','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117159','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117201','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117613','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117417','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105517','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117963','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118285','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105049','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119773','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119297','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119563','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116921','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116725','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116501','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119857','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119577','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105755','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118593','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115613','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116473','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118579','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105685','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116445','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117361','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105867','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105175','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116809','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115543','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115857','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116823','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118229','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105105','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117033','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117991','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105923','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117599','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115753','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116683','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117935','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119423','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118863','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116291','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119493','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105405','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118537','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118453','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116319','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116207','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105265','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105091','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119227','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115823','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116641','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116977','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116627','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118827','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118961','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105601','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105335','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119157','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116361','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118005','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115711','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118933','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119017','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115445','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118877','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119829','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118919','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118989','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117795','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119955','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119409','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105545','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116249','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118019','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115571','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115767','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117243','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119325','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115291','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115725','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116907','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105461','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115585','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117473','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105279','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105363','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105993','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117173','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116529','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105209','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118891','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115333','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105133','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116739','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105321','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116333','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105965','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116067','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105615','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105643','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117767','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117333','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105573','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117753','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119549','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119353','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105699','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17106007','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119185','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105769','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118411','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119507','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117131','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117781','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119367','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118845','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119885','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115599','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116431','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118621','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118089','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117823','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117061','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118243','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116277','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118551','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119087','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117445','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119479','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118737','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116389','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119311','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116963','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116543','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105937','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119801','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118773','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117229','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119339','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117487','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105077','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115361','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118159','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115927','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119619','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116193','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119171','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117019','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118117','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118201','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119591','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118187','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118173','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118764','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117515','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116053','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117075','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116571','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115627','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117005','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116417','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116613','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119031','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118341','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119255','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119129','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105391','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105419','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119745','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117103','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115983','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115347','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119045','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115277','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117809','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118975','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119759','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17106021','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105727','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105629','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118836','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115557','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115515','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117907','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116459','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117431','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105587','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105223','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105237','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17117117','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115417','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118782','1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105853','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116095','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17105825','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17115305','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17118033','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17116893','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD2 (Dyna CT)/DICOM/09112417/40300000/17119115','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594908','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592174','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589989','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585730','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595969','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592302','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597907','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593923','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598435','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588016','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590613','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596804','1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597236','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592483','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591758','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595020','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584322','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594940','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594668','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589349','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586343','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587552','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598883','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591870','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587079','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600547','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586887','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584242','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586167','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600499','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588000','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592350','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600083','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592771','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597539','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595921','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587968','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588480','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588400','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590229','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599207','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585250','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591982','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589301','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594092','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594124','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598099','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598563','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584530','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594620','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584466','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598947','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589733','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587920','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598355','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588176','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593987','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590117','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592286','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595404','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587904','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589381','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593235','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592675','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587175','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586775','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590133','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588752','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600451','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31582235','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589573','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587383','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595436','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594572','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596273','1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597763','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590437','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591374','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599779','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596996','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597156','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597092','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589008','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590389','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587191','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586631','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598691','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590309','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587632','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591406','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589493','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590798','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587047','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588192','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593651','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594892','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594524','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587255','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597859','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600099','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592451','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586071','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599587','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600643','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588672','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596385','1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598147','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600659','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589461','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590910','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598723','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590373','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587568','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589621','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585314','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590501','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584786','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593203','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594972','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593555','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593411','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597140','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595308','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600595','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596649','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591966','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600467','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586711','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597012','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584722','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589072','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595953','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591230','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588912','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588256','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586967','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592803','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593107','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591358','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594748','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596740','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593347','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586951','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593011','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589024','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596701','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587680','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599795','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599194','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596714','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597204','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594268','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588784','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593395','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592110','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599475','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587143','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598387','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599875','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592963','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593795','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598195','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588368','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594716','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593315','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595548','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596241','1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585698','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31582251','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595937','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589333','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598307','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595244','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593059','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593875','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595036','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587063','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598931','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588352','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588112','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591518','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590709','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587712','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597619','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592531','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590597','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593971','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591006','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589525','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587159','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599324','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591678','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592547','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595100','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586535','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600579','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584626','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594380','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599907','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599411','1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595340','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588448','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588960','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600403','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586199','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600707','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586647','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586663','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595484','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600371','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588416','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595212','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586423','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597108','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591182','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598803','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590565','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598163','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589253','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595761','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590677','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584834','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594604','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598979','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593587','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597523','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592467','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593603','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596820','1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596257','1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593859','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593939','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592094','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598483','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585959','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599427','1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597891','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588544','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596662','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599747','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591134','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584594','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587399','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591566','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591326','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595905','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585170','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587872','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598403','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587936','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595228','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592611','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592062','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593043','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587536','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597747','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586743','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585682','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587271','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596193','1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588160','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599827','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596209','1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586455','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598531','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599683','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585538','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588240','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597715','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584226','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587776','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591710','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588992','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599523','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590878','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591726','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598787','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593331','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585218','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598067','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588592','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587504','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591934','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593763','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599955','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590629','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591070','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591838','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594156','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592883','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586007','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588800','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590293','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584386','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599011','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586375','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590261','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589056','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589829','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596597','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589125','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589845','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588864','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588816','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594332','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588048','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597507','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591550','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588096','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588880','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595388','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600115','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586359','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585634','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585090','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591486','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592435','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598419','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587223','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584562','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585490','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592739','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587584','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588080','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591294','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591166','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590325','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596623','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587888','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592851','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593779','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600723','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592979','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595596','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597987','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585714','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597124','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589269','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595889','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598323','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587616','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585618','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593891','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598707','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591038','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588144','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598291','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586871','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594988','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588208','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598227','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589605','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594204','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598371','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595068','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586183','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598995','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596129','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586311','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595084','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597044','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589413','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585943','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593027','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587696','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600211','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592915','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599259','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584658','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586983','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591694','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589957','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585410','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585442','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594924','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588432','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585927','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599539','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584818','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586327','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587207','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593219','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598579','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591886','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587792','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596097','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594956','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592691','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585074','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592899','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597252','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590197','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589941','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594172','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593139','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595532','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597939','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596675','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590942','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584306','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586055','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600179','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596417','1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591422','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598547','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591278','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594284','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598627','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590862','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585746','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595500','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595260','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592254','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591118','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599987','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585234','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597635','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593491','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600307','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599043','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593667','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594108','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586791','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593187','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597923','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594812','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600163','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599027','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595052','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590245','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589749','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600323','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591614','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590517','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586503','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584850','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586487','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584418','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596636','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600419','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592787','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586679','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586823','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591742','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585586','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597683','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598035','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590782','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591086','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597172','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585847','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599220','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584754','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585186','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590149','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590469','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600227','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589701','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596980','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591662','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595873','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599971','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585831','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591918','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587031','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596852','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589205','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596481','1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585602','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592014','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585554','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588688','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588304','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584610','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591806','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590830','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597651','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599285','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587015','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595164','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588560','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597188','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584210','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592206','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597667','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598867','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586263','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588496','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585298','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596433','1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598739','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599350','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587239','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589893','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595713','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589397','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596900','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591102','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600387','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589221','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589557','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584578','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592238','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595292','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585042','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587856','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585522','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596932','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599075','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596353','1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596916','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598915','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586599','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592995','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591262','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600339','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600675','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597076','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592627','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599507','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586135','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595148','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584514','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593283','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587351','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590037','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599395','1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589765','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594348','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595132','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598243','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585863','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596497','1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599571','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585202','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592707','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593843','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594876','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600131','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586919','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594700','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585138','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584642','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594444','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598835','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584194','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595985','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594764','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593539','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591454','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584258','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594220','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593123','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587127','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592835','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598451','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594780','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592595','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595825','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597060','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589189','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590485','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591854','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598819','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590005','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595420','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593475','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600611','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591630','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592723','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585911','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586583','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597811','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590926','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598339','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599491','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590974','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590277','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588128','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596465','1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594252','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588944','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594476','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594140','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599298','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588928','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586039','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589445','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598515','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596401','1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592947','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593715','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599603','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585394','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596001','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585570','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588608','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591646','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589781','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595516','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593811','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600259','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593251','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588528','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599233','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598851','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596610','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594300','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584866','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589317','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598899','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597827','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599859','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599891','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585106','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592563','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591502','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588320','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591598','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593507','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587664','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593683','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585666','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596145','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594860','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591246','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597571','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594364','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597955','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588384','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595452','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589653','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588512','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594556','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599311','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584402','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595628','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590846','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586567','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584882','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591998','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595276','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593955','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588720','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599555','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589157','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597555','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589237','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584914','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596289','1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598115','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587984','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595468','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591950','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590085','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586935','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584770','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588288','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595564','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592366','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586279','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590069','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593635','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585895','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590181','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586615','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593459','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589541','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594844','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593267','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586407','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597971','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594412','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586727','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599619','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594828','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586231','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599923','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590421','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599443','1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590213','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594492','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588656','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591054','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588576','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595660','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586023','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594316','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596727','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587367','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593299','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592126','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591198','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595841','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598659','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593379','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584738','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589877','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592318','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587303','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596836','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591390','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585426','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588976','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599459','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586855','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587287','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595004','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589909','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584674','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591822','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587488','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590958','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591342','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596369','1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590357','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596964','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584930','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592419','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585506','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584290','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584898','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599843','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598003','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600243','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586391','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594732','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591150','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595777','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586807','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586759','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586087','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594540','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598675','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585010','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596321','1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595356','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596337','1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600483','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591470','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587335','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596065','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599246','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590405','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590165','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585026','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594636','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590549','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585282','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588896','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589173','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590021','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592867','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599715','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595180','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596081','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596571','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596584','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598755','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595324','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594076','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597699','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594188','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587095','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597220','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586151','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587648','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589589','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592190','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595809','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587808','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593827','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589925','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594508','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592499','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586903','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597587','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592046','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584978','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600003','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599272','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591438','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585458','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584994','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588768','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589797','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598051','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590661','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589141','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592931','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597779','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585650','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584482','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598179','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600563','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587111','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595612','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600627','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594396','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598643','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598131','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593363','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590053','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596449','1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587520','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596756','1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597795','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584690','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586551','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600291','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594003','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598499','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597603','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595196','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599811','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588736','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596113','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584706','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600019','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596017','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599337','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599699','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589685','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585122','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586439','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584450','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591310','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598611','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599363','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599091','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590894','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595793','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593443','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590101','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586519','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592755','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585378','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592078','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584434','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597731','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585362','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588464','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584546','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593747','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591022','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588224','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598275','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591582','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588624','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598467','1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584802','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592819','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596788','1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589040','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586103','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593171','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585346','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585474','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592222','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593091','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599379','1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599651','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598595','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591790','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589509','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585991','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596688','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589365','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600147','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595745','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592659','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600067','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586215','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592158','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596513','1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591774','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594684','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595729','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599181','1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594428','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591902','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600035','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591214','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587415','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589429','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599059','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590341','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589861','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598259','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598771','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585154','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593075','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596161','1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599667','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597843','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599635','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597028','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588064','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596868','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592030','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593571','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593907','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592270','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600691','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587840','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587824','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586695','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585058','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594236','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588832','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593619','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584370','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587600','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589717','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596948','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598019','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592515','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598963','1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600531','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592142','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594460','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590990','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594588','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592334','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588272','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600515','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586471','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596884','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587952','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598083','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584946','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585266','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596529','1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584354','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587760','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593731','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600195','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596305','1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600275','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590581','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593523','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596033','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600435','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584274','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584498','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587319','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31597875','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590645','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31591534','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600355','1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595116','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584962','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599763','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588336','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585975','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586247','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596558','1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588032','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589973','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586295','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589285','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595372','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594652','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590814','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588704','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595580','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592579','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596177','1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586839','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599939','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589669','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585879','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593155','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31592643','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595857','1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588640','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589477','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31598211','1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590533','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31599731','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596545','1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31595644','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589637','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586999','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31594796','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593427','1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31588848','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31585330','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31589813','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587728','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31600051','1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590453','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596225','1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596772','1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31584338','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31590693','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31596049','1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31593699','1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31586119','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390000/31587744','1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568347','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570842','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569445','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569393','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577590','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571076','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582539','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569003','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579462','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568477','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582897','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579332','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574305','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578890','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572997','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569055','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570738','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572373','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572191','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567385','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568815','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578760','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580939','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579202','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576099','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571362','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566631','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569549','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582795','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577467','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570868','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577668','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575631','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571232','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570530','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572711','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568737','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580627','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583563','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576973','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566709','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582963','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576359','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574643','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569939','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583589','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572815','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577077','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577441','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574539','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579124','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569237','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583095','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566527','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576768','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583199','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573907','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580835','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573829','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579020','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575553','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31584031','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567177','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573725','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575657','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569731','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571310','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582985','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575761','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574747','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574825','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578552','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582587','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547879','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583329','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574513','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581043','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580653','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570400','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576203','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575397','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572763','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580523','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571801','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574773','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568217','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580315','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547905','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568633','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569133','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569653','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567827','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566657','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569159','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583007','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578214','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571697','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583381','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567463','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570426','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571102','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569289','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577025','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547594','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570166','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570244','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577207','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575839','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575111','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577103','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575995','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580783','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569705','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583719','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571050','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574851','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566943','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581719','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581563','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573413','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581771','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574227','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582699','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575813','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580029','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570946','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569887','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582667','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582331','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583953','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569861','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31585762','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575787','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572347','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567775','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578136','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579540','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568035','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581511','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575267','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568087','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570296','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583771','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567931','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576151','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568243','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581069','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583225','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569029','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573985','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582031','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583407','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575033','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582941','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574565','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579743','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578968','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576456','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574617','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580445','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569263','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567645','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569497','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31584109','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575319','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581589','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581693','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574903','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576177','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581277','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577389','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578344','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578162','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547931','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570218','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576073','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575293','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582603','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573283','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580861','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583018','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568529','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568977','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575527','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568503','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567671','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576820','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579951','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567229','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575423','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583615','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547646','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570660','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578682','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566969','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568789','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567307','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581667','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582919','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579384','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568685','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568113','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573517','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574799','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567957','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572867','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578396','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580549','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576921','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575501','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576534','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582315','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568951','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569835','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578578','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567697','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577564','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570608','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574167','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566475','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577824','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573127','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572633','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578318','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581381','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571336','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578032','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583797','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572659','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575969','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569679','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566995','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583485','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571388','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576716','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570374','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567515','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576846','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578916','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577415','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567255','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579821','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569991','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582187','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580913','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570069','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580393','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582057','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573075','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573387','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575865','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575735','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583901','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572503','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582135','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583355','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578006','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575449','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578058','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567489','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575683','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574409','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569367','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583693','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570920','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578370','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573933','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571258','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572451','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580003','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577928','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579436','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576612','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582763','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569341','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575215','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579072','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581355','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578942','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581225','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547983','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582827','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582459','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567073','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580471','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577233','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578812','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573439','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567437','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577285','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572061','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579639','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572113','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570816','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577798','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576947','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582395','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573621','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571853','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582974','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572035','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547957','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582635','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579150','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574669','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571671','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571827','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573673','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578448','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577051','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579613','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577772','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580705','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582411','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583029','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567723','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582811','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570894','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583062','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579665','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573543','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567411','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573023','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572321','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580757','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575085','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581017','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575345','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566501','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575709','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579488','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579769','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547672','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568321','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583823','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582555','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582886','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582715','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572581','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547698','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574877','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581927','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580081','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583667','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567099','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568925','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580237','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574011','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573309','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577902','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582267','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574435','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578188','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571593','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575189','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31584083','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582779','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568295','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569523','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574695','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567619','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568191','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575891','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579795','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578838','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577954','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582083','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583641','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582651','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567749','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580055','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569471','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577616','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566865','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566891','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571645','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579691','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572945','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578084','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569107','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573699','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574461','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566449','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579925','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577538','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581537','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579514','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567203','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567879','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580809','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570270','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573101','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567593','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572139','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566735','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580601','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576385','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574487','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583040','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574981','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570556','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574253','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583147','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576229','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568555','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578474','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570504','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581823','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573335','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582299','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570140','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580419','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575475','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31585778','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582747','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571492','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579228','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581953','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571466','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581459','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568399','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573881','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576333','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567281','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571983','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580497','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579358','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570192','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583251','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567567','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571128','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573959','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547568','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567333','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581095','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572685','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583927','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567853','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569913','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574279','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576586','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576047','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568165','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572529','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572971','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575371','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581147','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580159','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571518','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571619','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570764','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579717','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573361','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578292','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581251','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583979','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583849','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583084','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571440','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569211','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567047','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573205','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575059','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582908','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574929','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568139','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577876','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573855','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578110','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577642','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573257','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570712','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582161','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571024','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577746','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575007','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582475','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569185','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581745','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575163','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575579','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566605','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583173','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578266','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583073','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570582','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580133','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576690','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572607','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569575','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582283','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568061','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580965','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580679','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582843','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582930','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566553','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581199','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569081','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583875','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567359','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577694','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547853','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569315','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576021','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567021','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574357','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567151','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571775','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566917','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583277','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574115','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577311','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579098','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582363','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568451','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576281','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571154','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547542','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576638','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582507','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578240','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578994','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573803','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571957','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579847','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580185','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568659','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577337','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578526','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568425','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572269','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576742','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568269','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574591','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566813','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573491','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568763','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547620','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574063','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573465','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577980','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576125','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580263','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580991','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568711','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576794','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573569','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566761','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576255','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566579','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574331','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581407','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570452','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582571','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580575','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583433','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576482','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582683','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581615','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579254','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568009','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570790','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583537','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575137','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581979','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568899','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572477','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568607','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574141','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582109','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572399','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570972','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572087','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579306','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578708','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575241','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582005','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574089','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581485','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569809','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579280','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547769','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578422','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578630','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572243','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582731','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569783','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570686','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567801','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572555','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577850','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571414','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578604','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580211','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579410','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576664','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572919','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578500','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582491','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574955','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579046','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547516','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581303','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576307','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573153','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579873','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583303','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572217','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570998','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566839','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580887','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570017','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572789','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583511','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31547827','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571180','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571749','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572893','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567983','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579176','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581329','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577363','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579977','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581173','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571284','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574383','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570043','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575605','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577259','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567905','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577129','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569965','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582875','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571931','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581875','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573647','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574037','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568373','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581641','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575917','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576999','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570634','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582859','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580367','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581901','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577155','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581121','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31574721','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570322','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580107','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582952','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568841','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582347','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31579899','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582427','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569757','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567125','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570348','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566683','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573751','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573231','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31575943','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583121','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569627','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571206','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569419','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576508','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572295','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573049','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578734','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572841','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581433','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572425','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581797','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31581849','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31566787','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573595','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31568581','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572737','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582379','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580341','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31584005','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578656','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582619','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583745','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582523','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31570478','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573777','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31567541','1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578864','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580731','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31569601','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572009','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31578786','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577720','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571905','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31572165','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31576560','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31584057','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583459','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582996','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31573179','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571879','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31577181','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31582443','1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31571723','1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31580289','1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080');
+INSERT INTO "Images" VALUES('CD1/DICOM/09112417/37390001/31583051','1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147');
+CREATE TABLE 'Patients' (   'UID' INTEGER PRIMARY KEY AUTOINCREMENT,   'PatientsName' VARCHAR(255) NULL ,   'PatientID' VARCHAR(255) NULL ,   'PatientsBirthDate' DATE NULL ,   'PatientsBirthTime' TIME NULL ,   'PatientsSex' varchar(1) NULL ,   'PatientsComments' VARCHAR(255) NULL, 'PatientsAge' varchar(10) NULL );
+INSERT INTO "Patients" VALUES(14,'Austrialian','8775070',20060101,10100,'M','A volunteer','35');
+INSERT INTO "Patients" VALUES(15,'09.11.24-14:36:24-STD','09.11.24-14:36:24-STD-4.0.4094797',18581118,'','O','','78');
+INSERT INTO "Patients" VALUES(16,'MROVERLAY-13','09.11.24-14:37:10-STD-1.3.12.2.1107.5.2.31.30287',19560304,'','O','','102');
+CREATE TABLE 'Series' (   'SeriesInstanceUID' VARCHAR(255) NOT NULL ,   'StudyInstanceUID' VARCHAR(45) NOT NULL ,   'SeriesNumber' INT NULL ,   'SeriesDate' DATE NULL ,   'SeriesTime' VARCHAR(20) NULL ,   'SeriesDescription' VARCHAR(255) NULL ,   'BodyPartExamined' VARCHAR(255) NULL ,   'FrameOfReferenceUID' VARCHAR(255) NULL ,   'AcquisitionNumber' INT NULL ,   'ContrastAgent' VARCHAR(255) NULL ,   'ScanningSequence' VARCHAR(45) NULL ,   'EchoNumber' INT NULL ,   'TemporalPosition' INT NULL ,   PRIMARY KEY ('SeriesInstanceUID') );
+INSERT INTO "Series" VALUES('1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058','1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',123456,'','','None','','',0,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173529.684000','DynaCT Nat Fill HU Normal [InSpace3D]','','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000394',1,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173453.699000','Images for VOI selection','','',1,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',17,'2009-11-24','160901.687000','t1_spc_WIP537_cor_body','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416173969227026001.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',18,'2009-11-24','161741.952000','t1_spc_WIP537_cor_surface','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112417165423402928463.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',20,'2009-11-24','171701.952000','t1_spc_WIP537_cor_surface_PreScanNormalize_Needle','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415160557860924767.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',9,'2009-11-24','151607.280000','t1_se_ax_OFF_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415015166452324206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',5,'2009-11-24','150154.798000','t2_spc_ns_sag_p2_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415075486124424445.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',6,'2009-11-24','150756.655000','t1_se_ax_OFF_iso','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416354054128327388.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',19,'2009-11-24','163552.202000','t1_spc_WIP537_cor_surface_PreScanNormalize','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415493132049125056.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',16,'2009-11-24','154932.124000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415122398728824565.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',7,'2009-11-24','151226.577000','VIBE_1x1x1_body','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414575190620223971.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',4,'2009-11-24','145754.627000','VIBE_1x1x1_body','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414562789689323766.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',3,'2009-11-24','145630.752000','VIBE_1x1x1','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415141429610124694.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',8,'2009-11-24','151416.108000','t1_se_ax_OFF_iso_body','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414440663007822537.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',1,'2009-11-24','144410.799000','SCOUT','','1.3.12.2.1107.5.2.31.30287.2.20091124143837049.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415201967481224864.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',11,'2009-11-24','152020.233000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415221047088724889.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',12,'2009-11-24','152211.187000','t1_se_ax_OFF_2mm','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415433060459424973.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',15,'2009-11-24','154334.780000','SCOUT','','1.3.12.2.1107.5.2.31.30287.2.20091124154153702.0.0.0',1,'','GR',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112414480531183523134.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',2,'2009-11-24','144806.174000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415175721344424833.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',10,'2009-11-24','151758.015000','t1_se_ax_OFF','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415240124326224925.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',13,'2009-11-24','152401.983000','t1_se_ax_OFF_2mm_body','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112415255430595124964.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',14,'2009-11-24','152554.999000','t1_se_ax_OFF_2mm','','1.3.12.2.1107.5.2.31.30287.1.20091124143837049.0.0.4950',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000003549','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',103,'2009-11-24','171811.576000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000002726','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',102,'2009-11-24','163724.171000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001903','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',101,'2009-11-24','162255.999000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112412545103000000147','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',99,'2009-11-24','170811.702000','PhoenixZIPReport','','',0,'','',0,0);
+INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112415082031000001080','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',100,'2009-11-24','162146.108000','','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);
+CREATE TABLE 'Studies' (   'StudyInstanceUID' VARCHAR(255) NOT NULL ,   'PatientsUID' INT NOT NULL ,   'StudyID' VARCHAR(255) NULL ,   'StudyDate' DATE NULL ,   'StudyTime' VARCHAR(20) NULL ,   'AccessionNumber' VARCHAR(255) NULL ,   'ModalitiesInStudy' VARCHAR(255) NULL ,   'InstitutionName' VARCHAR(255) NULL , 'ReferringPhysician' VARCHAR(255) NULL ,  'PerformingPhysiciansName' VARCHAR(255) NULL , 'StudyDescription' VARCHAR(255) NULL ,  PRIMARY KEY ('StudyInstanceUID') );
+INSERT INTO "Studies" VALUES('1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',14,'123456','2009-01-02','010100.000000','1','','Hospital YYY', 'Unknown','me','None');
+INSERT INTO "Studies" VALUES('1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',15,'Default StudyID','2009-11-24','143624.000000','','','Hospital XXX', '','you','');
+INSERT INTO "Studies" VALUES('1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',16,'2','2009-11-24','143836.908000','','','Hospital XXX', 'IORDACHITA','her','Carrino^MR_Overlay');
+DELETE FROM sqlite_sequence;
+INSERT INTO "sqlite_sequence" VALUES('Patients',16);
+
+CREATE TABLE 'Directories' (
+  'Dirname' VARCHAR(1024) ,
+  PRIMARY KEY ('Dirname') );
+
+COMMIT;
diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index c8bdd9b92c..b93920dc61 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -6,12 +6,16 @@
 --       commands per QSqlQuery::exec call!
 -- ;
 
+DROP TABLE IF EXISTS 'SchemaInfo' ;
 DROP TABLE IF EXISTS 'Images' ;
 DROP TABLE IF EXISTS 'Patients' ;
 DROP TABLE IF EXISTS 'Series' ;
 DROP TABLE IF EXISTS 'Studies' ;
 DROP TABLE IF EXISTS 'Directories' ;
 
+CREATE TABLE 'SchemaInfo' ( 'Version' VARCHAR(1024) NOT NULL );
+INSERT INTO 'SchemaInfo' VALUES('0.5');
+
 CREATE TABLE 'Images' (
   'SOPInstanceUID' VARCHAR(64) NOT NULL,
   'Filename' VARCHAR(1024) NOT NULL ,
diff --git a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
index 23a6a39ab7..b35fde5fee 100644
--- a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
+++ b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
@@ -4,6 +4,7 @@ create_test_sourcelist(Tests ${KIT}CppTests.cpp
   ctkDICOMCoreTest1.cpp
   ctkDICOMDatabaseTest1.cpp
   ctkDICOMDatabaseTest2.cpp
+  ctkDICOMDatabaseTest3.cpp
   ctkDICOMDatasetTest1.cpp
   ctkDICOMIndexerTest1.cpp
   ctkDICOMModelTest1.cpp
@@ -31,6 +32,9 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME})
 # ctkDICOMDatabase
 SIMPLE_TEST(ctkDICOMDatabaseTest1)
 SIMPLE_TEST(ctkDICOMDatabaseTest2 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)
+SIMPLE_TEST(ctkDICOMDatabaseTest3
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../Resources/dicom-old-schema.sql
+  )
 SIMPLE_TEST(ctkDICOMDatasetTest1)
 SIMPLE_TEST(ctkDICOMIndexerTest1 )
 
diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest3.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest3.cpp
new file mode 100644
index 0000000000..b23fb232d8
--- /dev/null
+++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest3.cpp
@@ -0,0 +1,114 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  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.
+
+=========================================================================*/
+
+// Qt includes
+#include 
+#include 
+
+// ctkDICOMCore includes
+#include "ctkDICOMDatabase.h"
+
+// STD includes
+#include 
+#include 
+
+
+int ctkDICOMDatabaseTest3( int argc, char * argv [] )
+{
+  QCoreApplication app(argc, argv);
+
+  if (argc <= 1)
+    {
+    std::cerr << "Warning, no sql file given. Test stops" << std::endl;
+    std::cerr << "Usage: ctkDICOMDatabaseTest3 " << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  QDir databaseDirectory = QDir::temp();
+  databaseDirectory.remove("ctkDICOMDatabase.sql");
+
+  QFileInfo databaseFile(databaseDirectory, QString("database.test"));
+  QString databaseFileName(databaseFile.absoluteFilePath());
+  
+  std::cerr << "Populating database " << databaseFileName.toStdString() << "\n";
+
+  // first, create a database and initialize it with the old schema
+  try
+  {
+    ctkDICOMDatabase myCTK( databaseFileName );
+
+    if (!myCTK.initializeDatabase(argv[1]))
+    {
+      std::cerr << "Error when initializing the data base with: " << argv[1]
+          << " error: " << myCTK.lastError().toStdString();
+      return EXIT_FAILURE;
+    }
+
+    if ( myCTK.schemaVersionLoaded() != QString("") )
+    {
+      std::cerr << "Schema tag should be empty in old schema\n";
+      std::cerr << "Instead we got: (" << myCTK.schemaVersionLoaded().toStdString() << ")\n";
+      return EXIT_FAILURE;
+    }
+
+    myCTK.closeDatabase();
+  }
+  catch (std::exception e)
+    {
+    std::cerr << "Error when opening the data base file: " << databaseFileName.toStdString()
+        << " error: " << e.what();
+    return EXIT_FAILURE;
+    }
+
+  // now try opening it and updating the schema 
+  try
+  {
+    ctkDICOMDatabase myCTK( databaseFileName );
+
+    if ( myCTK.schemaVersionLoaded() == myCTK.schemaVersion() )
+    {
+      std::cerr << "Schema version should Not match\n";
+      return EXIT_FAILURE;
+    }
+
+    if ( !myCTK.updateSchema() )
+    {
+      std::cerr << "Could not update schema\n";
+      return EXIT_FAILURE;
+    }
+
+    if ( myCTK.schemaVersionLoaded() != myCTK.schemaVersion() )
+    {
+      std::cerr << "Schema version should match\n";
+      return EXIT_FAILURE;
+    }
+
+    myCTK.closeDatabase();
+  }
+  catch (std::exception e)
+    {
+    std::cerr << "Error when re-opening the data base file: " << databaseFileName.toStdString()
+        << " error: " << e.what();
+    return EXIT_FAILURE;
+    }
+
+
+  return EXIT_SUCCESS;
+}
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index f659822fba..03d0dce29b 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -118,6 +118,9 @@ class ctkDICOMDatabasePrivate
   QString LastSeriesInstanceUID;
   int LastPatientUID;
 
+  /// resets the variables to new inserts won't be fooled by leftover values
+  void resetLastInsertedValues();
+
   /// parallel inserts are not allowed (yet)
   QMutex insertMutex;
 
@@ -142,8 +145,19 @@ ctkDICOMDatabasePrivate::ctkDICOMDatabasePrivate(ctkDICOMDatabase& o): q_ptr(&o)
 {
   this->thumbnailGenerator = NULL;
   this->LoggedExecVerbose = false;
-  this->LastPatientUID = -1;
   this->TagCacheVerified = false;
+  this->resetLastInsertedValues();
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMDatabasePrivate::resetLastInsertedValues()
+{
+  this->LastPatientID = QString("");
+  this->LastPatientsName = QString("");
+  this->LastPatientsBirthDate = QString("");
+  this->LastStudyInstanceUID = QString("");
+  this->LastSeriesInstanceUID = QString("");
+  this->LastPatientUID = -1;
 }
 
 //------------------------------------------------------------------------------
@@ -246,6 +260,9 @@ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& c
           return;
         }
     }
+  d->resetLastInsertedValues();
+
+
   if (!isInMemory())
     {
       QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList(databaseFile),this);
@@ -382,9 +399,46 @@ QStringList ctkDICOMDatabasePrivate::filenames(QString table)
 bool ctkDICOMDatabase::initializeDatabase(const char* sqlFileName)
 {
   Q_D(ctkDICOMDatabase);
+
+  d->resetLastInsertedValues();
+
+  // remove any existing schema info - this handles the case where an
+  // old schema should be loaded for testing.
+  QSqlQuery dropSchemaInfo(d->Database);
+  d->loggedExec( dropSchemaInfo, QString("DROP TABLE IF EXISTS 'SchemaInfo';") );
   return d->executeScript(sqlFileName);
 }
 
+//------------------------------------------------------------------------------
+QString ctkDICOMDatabase::schemaVersionLoaded()
+{
+  Q_D(ctkDICOMDatabase);
+  /// look for the version info in the database
+  QSqlQuery versionQuery(d->Database);
+  if ( !d->loggedExec( versionQuery, QString("SELECT Version from SchemaInfo;") ) )
+    {
+    return QString("");
+    }
+
+  if (versionQuery.next())
+    {
+    return versionQuery.value(0).toString();
+    }
+
+  return QString("");
+}
+
+
+//------------------------------------------------------------------------------
+bool ctkDICOMDatabase::updateSchemaIfNeeded(const char* schemaFile)
+{
+  if ( schemaVersionLoaded() != schemaVersion() )
+    {
+    return this->updateSchema(schemaFile);
+    }
+  return false;
+}
+
 //------------------------------------------------------------------------------
 bool ctkDICOMDatabase::updateSchema(const char* schemaFile)
 {
@@ -395,16 +449,26 @@ bool ctkDICOMDatabase::updateSchema(const char* schemaFile)
   Q_D(ctkDICOMDatabase);
   d->createBackupFileList();
  
+  d->resetLastInsertedValues();
   this->initializeDatabase(schemaFile);
 
   QStringList allFiles = d->filenames("Filenames_backup");
+  emit schemaUpdateStarted(allFiles.length());
+  
+  int progressValue = 0;
   foreach(QString file, allFiles)
   {
+    emit schemaUpdateProgress(progressValue);
+    emit schemaUpdateProgress(file);
+
     // TODO: use QFuture
     this->insert(file,false,false,true);
+
+    progressValue++;
   }
   // TODO: check better that everything is ok
   d->removeBackupFileList();
+  emit schemaUpdated();
   return true;
 
 }
@@ -1203,7 +1267,7 @@ bool ctkDICOMDatabase::removeSeries(const QString& seriesInstanceUID)
 
   this->cleanup();
 
-  d->LastSeriesInstanceUID = "";
+  d->resetLastInsertedValues();
 
   return true;
 }
@@ -1242,7 +1306,7 @@ bool ctkDICOMDatabase::removeStudy(const QString& studyInstanceUID)
           result = false;
         }
     }
-  d->LastStudyInstanceUID = "";
+  d->resetLastInsertedValues();
   return result;
 }
 
@@ -1269,10 +1333,7 @@ bool ctkDICOMDatabase::removePatient(const QString& patientID)
           result = false;
         }
     }
-  d->LastPatientID = "";
-  d->LastPatientsName = "";
-  d->LastPatientsBirthDate = "";
-  d->LastPatientUID = -1;
+  d->resetLastInsertedValues();
   return result;
 }
 
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h
index 843532bf8d..19d210d377 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.h
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.h
@@ -100,8 +100,9 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   ///        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.
+  /// @param update the schema if it is found to be out of date
   Q_INVOKABLE virtual void openDatabase(const QString databaseFile,
-                                        const QString& connectionName = "DICOM-DB" );
+                                        const QString& connectionName = "DICOM-DB");
 
   ///
   /// close the database. It must not be used afterwards.
@@ -113,6 +114,17 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   /// updates the database schema and reinserts all existing files
   Q_INVOKABLE bool updateSchema(const char* schemaFile = ":/dicom/dicom-schema.sql");
 
+  /// updates the database schema only if the versions don't match
+  /// Returns true if schema was updated
+  Q_INVOKABLE bool updateSchemaIfNeeded(const char* schemaFile = ":/dicom/dicom-schema.sql");
+
+  /// returns the schema version needed by the current version of this code
+  Q_INVOKABLE QString schemaVersion() { return QString("0.5"); };
+
+  /// returns the schema version for the currently open database
+  /// in order to support schema updating
+  Q_INVOKABLE QString schemaVersionLoaded();
+
   ///
   /// \brief database accessors
   Q_INVOKABLE QStringList patients ();
@@ -201,6 +213,13 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
 
 Q_SIGNALS:
   void databaseChanged();
+  /// Indicates that the schema is about to be updated and how many files will be processed
+  void schemaUpdateStarted(int);
+  /// Indicates progress in updating schema (int is file number, string is file name)
+  void schemaUpdateProgress(int);
+  void schemaUpdateProgress(QString);
+  /// Indicates schema update finished
+  void schemaUpdated();
 
 protected:
   QScopedPointer d_ptr;
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
index 87cfdef5e8..9c822f1713 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
@@ -192,6 +192,54 @@ ctkDICOMAppWidget::~ctkDICOMAppWidget()
   d->ImportDialog->deleteLater();
 }
 
+//----------------------------------------------------------------------------
+void ctkDICOMAppWidget::updateDatabaseSchemaIfNeeded()
+{
+
+  Q_D(ctkDICOMAppWidget);  
+
+  if ( d->DICOMDatabase->schemaVersion() != d->DICOMDatabase->schemaVersionLoaded() )
+    {
+    QProgressDialog* progress = new QProgressDialog("DICOM Schema Update", "Cancel", 0, 100, this,
+                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+    // We don't want the progress dialog to resize itself, so we bypass the label
+    // by creating our own
+    QLabel* progressLabel = new QLabel(tr("Initialization..."));
+    progress->setLabel(progressLabel);
+#ifdef Q_WS_MAC
+    // BUG: avoid deadlock of dialogs on mac
+    progress->setWindowModality(Qt::NonModal);
+#else
+    progress->setWindowModality(Qt::ApplicationModal);
+#endif
+    progress->setMinimumDuration(0);
+    progress->setValue(0);
+    progress->show();
+
+    // TODO - cancel?
+    //connect(progress, SIGNAL(canceled()), d->DICOMIndexer.data(), SLOT(cancel()));
+
+    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateStarted(int)),
+            progress, SLOT(setMaximum(int)));
+    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(int)),
+            progress, SLOT(setValue(int)));
+    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(QString)),
+            progressLabel, SLOT(setText(QString)));
+    connect(d->DICOMDatabase.data(), SIGNAL(progress(int)),
+            this, SLOT(onProgress(int)));
+
+    // close the dialog
+    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdated()),
+            progress, SLOT(close()));
+    // reset the database to show new data
+    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdated()),
+            &d->DICOMModel, SLOT(reset()));
+
+    d->DICOMDatabase->updateSchema();
+    }
+
+}
+
 //----------------------------------------------------------------------------
 void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
 {
@@ -216,6 +264,9 @@ void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
     d->DICOMDatabase->closeDatabase();
     return;
     }
+
+  // update the database schema if needed and provide progress
+  this->updateDatabaseSchemaIfNeeded();
   
   d->DICOMModel.setDatabase(d->DICOMDatabase->database());
   d->DICOMModel.setEndLevel(ctkDICOMModel::SeriesType);
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
index 8861efeb4b..0fb40f0675 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
@@ -44,6 +44,11 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMAppWidget : public QWidget
 
   QString databaseDirectory() const;
 
+  /// Updates schema of loaded database to match the one
+  /// coded by the current version of ctkDICOMDatabase.
+  /// Also provides a dialog box for progress
+  void updateDatabaseSchemaIfNeeded();
+
   /// Setting search widget pop-up mode
   /// Default value is false. Setting it to true will make
   /// search widget to be displayed as pop-up widget

From 956d83e4bbadddfd313bd13cbc8ecf02ea6c2a63 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 15:52:52 -0400
Subject: [PATCH 066/247] Speedup database inserts as suggested by Andras Lasso

See slicerrt issue #24

https://www.assembla.com/spaces/slicerrt/tickets/24
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 03d0dce29b..aec9b99908 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -262,13 +262,17 @@ void ctkDICOMDatabase::openDatabase(const QString databaseFile, const QString& c
     }
   d->resetLastInsertedValues();
 
-
   if (!isInMemory())
     {
       QFileSystemWatcher* watcher = new QFileSystemWatcher(QStringList(databaseFile),this);
       connect(watcher, SIGNAL(fileChanged(QString)),this, SIGNAL (databaseChanged()) );
     }
 
+  //Disable synchronous writing to make modifications faster
+  QSqlQuery pragmaSyncQuery(d->Database);
+  pragmaSyncQuery.exec("PRAGMA synchronous = OFF");
+  pragmaSyncQuery.finish();
+
   // set up the tag cache for use later
   QFileInfo fileInfo(d->DatabaseFileName);
   d->TagCacheDatabaseFilename = QString( fileInfo.dir().path() + "/ctkDICOMTagCache.sql" );
@@ -1345,6 +1349,7 @@ bool ctkDICOMDatabase::removePatient(const QString& patientID)
 bool ctkDICOMDatabase::tagCacheExists()
 {
   Q_D(ctkDICOMDatabase);
+
   if (d->TagCacheVerified)
     {
     return true;
@@ -1362,6 +1367,12 @@ bool ctkDICOMDatabase::tagCacheExists()
       qDebug() << "TagCacheDatabaseFilename is: " << d->TagCacheDatabaseFilename << "\n";
       return false;
       }
+
+    //Disable synchronous writing to make modifications faster
+    QSqlQuery pragmaSyncQuery(d->TagCacheDatabase);
+    pragmaSyncQuery.exec("PRAGMA synchronous = OFF");
+    pragmaSyncQuery.finish();
+
     }
 
   // check that the table exists

From b00c7cadc9a818748ab6bb90f31a0ea8010556bd Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 15:59:29 -0400
Subject: [PATCH 067/247] Fix missing modality field from update sample
 database

Aparently this series row was not updated when the rest of the
sample was updated with the new schema.
---
 Libs/DICOM/Core/Resources/dicom-sample.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/Resources/dicom-sample.sql b/Libs/DICOM/Core/Resources/dicom-sample.sql
index 376509a31e..ed3140ab9e 100644
--- a/Libs/DICOM/Core/Resources/dicom-sample.sql
+++ b/Libs/DICOM/Core/Resources/dicom-sample.sql
@@ -2234,7 +2234,7 @@ INSERT INTO "Patients" VALUES(14,'Austrialian','8775070',20060101,10100,'M','A v
 INSERT INTO "Patients" VALUES(15,'09.11.24-14:36:24-STD','09.11.24-14:36:24-STD-4.0.4094797',18581118,'','O','','78');
 INSERT INTO "Patients" VALUES(16,'MROVERLAY-13','09.11.24-14:37:10-STD-1.3.12.2.1107.5.2.31.30287',19560304,'','O','','102');
 CREATE TABLE 'Series' (   'SeriesInstanceUID' VARCHAR(255) NOT NULL ,   'StudyInstanceUID' VARCHAR(45) NOT NULL ,   'SeriesNumber' INT NULL ,   'SeriesDate' DATE NULL ,   'SeriesTime' VARCHAR(20) NULL ,   'SeriesDescription' VARCHAR(255) NULL ,   'Modality' VARCHAR(20) NULL ,   'BodyPartExamined' VARCHAR(255) NULL ,   'FrameOfReferenceUID' VARCHAR(255) NULL ,   'AcquisitionNumber' INT NULL ,   'ContrastAgent' VARCHAR(255) NULL ,   'ScanningSequence' VARCHAR(45) NULL ,   'EchoNumber' INT NULL ,   'TemporalPosition' INT NULL ,   PRIMARY KEY ('SeriesInstanceUID') );
-INSERT INTO "Series" VALUES('1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058','1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',123456,'','','None','','',0,'','',0,0);
+INSERT INTO "Series" VALUES('1.2.826.0.1.3680043.2.1125.1.65375240934815452318141136507497058','1.2.826.0.1.3680043.2.1125.1.73379483469717886505187028001198162',123456,'','','None','','','',0,'','',0,0);
 INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420245387500000395','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173529.684000','DynaCT Nat Fill HU Normal [InSpace3D]','CT','','1.3.12.2.1107.5.4.7.6975.30000009112420245387500000394',1,'','',0,0);
 INSERT INTO "Series" VALUES('1.3.12.2.1107.5.4.7.6975.30000009112420241301500000022','1.3.12.2.1107.5.4.5.50096.30000009112417295950800000029',1,'2009-11-24','173453.699000','Images for VOI selection','CT','','',1,'','',0,0);
 INSERT INTO "Series" VALUES('1.3.12.2.1107.5.2.31.30287.2009112416085385445425206.0.0.0','1.3.12.2.1107.5.2.31.30287.30000009112412540589000000011',17,'2009-11-24','160901.687000','t1_spc_WIP537_cor_body','MR','','1.3.12.2.1107.5.2.31.30287.1.20091124154153702.0.0.5014',1,'','SE',1,0);

From 5fab487c193f060b7155b3db29d332cc4c402873 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Mon, 23 Jul 2012 16:28:03 -0400
Subject: [PATCH 068/247] Improve names for sample files

Use 'unversioned' rather than 'old' per suggestion
from Andras Lasso.
---
 ...ample-old-schema.sql => dicom-sample-unversioned-schema.sql} | 0
 .../{dicom-old-schema.sql => dicom-unversioned-schema.sql}      | 0
 Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt                      | 2 +-
 3 files changed, 1 insertion(+), 1 deletion(-)
 rename Libs/DICOM/Core/Resources/{dicom-sample-old-schema.sql => dicom-sample-unversioned-schema.sql} (100%)
 rename Libs/DICOM/Core/Resources/{dicom-old-schema.sql => dicom-unversioned-schema.sql} (100%)

diff --git a/Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql b/Libs/DICOM/Core/Resources/dicom-sample-unversioned-schema.sql
similarity index 100%
rename from Libs/DICOM/Core/Resources/dicom-sample-old-schema.sql
rename to Libs/DICOM/Core/Resources/dicom-sample-unversioned-schema.sql
diff --git a/Libs/DICOM/Core/Resources/dicom-old-schema.sql b/Libs/DICOM/Core/Resources/dicom-unversioned-schema.sql
similarity index 100%
rename from Libs/DICOM/Core/Resources/dicom-old-schema.sql
rename to Libs/DICOM/Core/Resources/dicom-unversioned-schema.sql
diff --git a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
index b35fde5fee..ef2ff20292 100644
--- a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
+++ b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
@@ -33,7 +33,7 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME})
 SIMPLE_TEST(ctkDICOMDatabaseTest1)
 SIMPLE_TEST(ctkDICOMDatabaseTest2 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)
 SIMPLE_TEST(ctkDICOMDatabaseTest3
-  ${CMAKE_CURRENT_SOURCE_DIR}/../../Resources/dicom-old-schema.sql
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../Resources/dicom-unversioned-schema.sql
   )
 SIMPLE_TEST(ctkDICOMDatasetTest1)
 SIMPLE_TEST(ctkDICOMIndexerTest1 )

From 6b0da75ee6cb1c4962dd20868d12ae18f43d62b3 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Tue, 24 Jul 2012 04:53:42 -0400
Subject: [PATCH 069/247] Fix warning "delete-non-virtual-dtor-warnings" gcc-47
 warnings

See issue #207
---
 Libs/Core/Testing/Cpp/ctkSingletonTestHelper.cpp       |  5 +++++
 Libs/Core/Testing/Cpp/ctkSingletonTestHelper.h         |  5 +++--
 Libs/Core/ctkAbstractFactory.h                         |  1 +
 Libs/Core/ctkAbstractFactory.tpp                       |  6 ++++++
 .../VTK/Core/ctkVTKObjectEventsObserver.cpp            | 10 ++++++++++
 .../VTK/Core/ctkVTKObjectEventsObserver.h              |  2 ++
 Libs/Widgets/ctkThumbnailLabel.cpp                     |  6 ++++++
 7 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.cpp b/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.cpp
index 8d8e354885..c9f321d4c8 100644
--- a/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.cpp
+++ b/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.cpp
@@ -50,6 +50,11 @@ ctkSingletonTestHelper::ctkSingletonTestHelper() : d_ptr(new ctkSingletonTestHel
 {
 }
 
+//-----------------------------------------------------------------------------
+ctkSingletonTestHelper::~ctkSingletonTestHelper()
+{
+}
+
 //-----------------------------------------------------------------------------
 ctkSingletonTestHelper* ctkSingletonTestHelper::instance()
 {
diff --git a/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.h b/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.h
index 601d305aa8..b9fe9b34df 100644
--- a/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.h
+++ b/Libs/Core/Testing/Cpp/ctkSingletonTestHelper.h
@@ -33,8 +33,6 @@ class ctkSingletonTestHelperPrivate;
 class ctkSingletonTestHelper
 {
 public:
-  ctkSingletonTestHelper();
-  
   static ctkSingletonTestHelper* instance();
   
   // Add singleton method here ...
@@ -42,6 +40,9 @@ class ctkSingletonTestHelper
   int northFaceCount()const;
   
 protected:
+  ctkSingletonTestHelper();
+  virtual ~ctkSingletonTestHelper();
+  
   CTK_SINGLETON_DECLARE(ctkSingletonTestHelper);
   QScopedPointer d_ptr;
   
diff --git a/Libs/Core/ctkAbstractFactory.h b/Libs/Core/ctkAbstractFactory.h
index f3d0ba647e..f7a1c5670f 100644
--- a/Libs/Core/ctkAbstractFactory.h
+++ b/Libs/Core/ctkAbstractFactory.h
@@ -44,6 +44,7 @@ class ctkAbstractFactoryItem
 public:
   //explicit ctkAbstractFactoryItem();
   ctkAbstractFactoryItem();
+  virtual ~ctkAbstractFactoryItem();
 
   virtual bool load() = 0;
 
diff --git a/Libs/Core/ctkAbstractFactory.tpp b/Libs/Core/ctkAbstractFactory.tpp
index c4552a92a1..56f01c1b7e 100644
--- a/Libs/Core/ctkAbstractFactory.tpp
+++ b/Libs/Core/ctkAbstractFactory.tpp
@@ -38,6 +38,12 @@ ctkAbstractFactoryItem::ctkAbstractFactoryItem()
   this->Verbose = false;
 }
 
+//----------------------------------------------------------------------------
+template
+ctkAbstractFactoryItem::~ctkAbstractFactoryItem()
+{
+}
+
 //----------------------------------------------------------------------------
 template
 QStringList ctkAbstractFactoryItem::instantiateErrorStrings()const
diff --git a/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.cpp b/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.cpp
index 893bb57d0c..1a6f70650c 100644
--- a/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.cpp
+++ b/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.cpp
@@ -56,6 +56,16 @@ void ctkVTKConnectionFactory::setInstance(ctkVTKConnectionFactory* newInstance)
   Self::Instance = newInstance;
 }
 
+//-----------------------------------------------------------------------------
+ctkVTKConnectionFactory::ctkVTKConnectionFactory()
+{
+}
+
+//-----------------------------------------------------------------------------
+ctkVTKConnectionFactory::~ctkVTKConnectionFactory()
+{
+}
+
 //-----------------------------------------------------------------------------
 ctkVTKConnection* ctkVTKConnectionFactory::createConnection(ctkVTKObjectEventsObserver* parent)const
 {
diff --git a/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.h b/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.h
index 30c4a9633b..12008410b8 100644
--- a/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.h
+++ b/Libs/Visualization/VTK/Core/ctkVTKObjectEventsObserver.h
@@ -54,6 +54,8 @@ class CTK_VISUALIZATION_VTK_CORE_EXPORT ctkVTKConnectionFactory
 
   virtual ctkVTKConnection* createConnection(ctkVTKObjectEventsObserver*)const;
 protected:
+  ctkVTKConnectionFactory();
+  virtual ~ctkVTKConnectionFactory();
   CTK_SINGLETON_DECLARE(ctkVTKConnectionFactory)
 };
 CTK_SINGLETON_DECLARE_INITIALIZER(CTK_VISUALIZATION_VTK_CORE_EXPORT, ctkVTKConnectionFactory)
diff --git a/Libs/Widgets/ctkThumbnailLabel.cpp b/Libs/Widgets/ctkThumbnailLabel.cpp
index e2ddca4099..71879d211a 100644
--- a/Libs/Widgets/ctkThumbnailLabel.cpp
+++ b/Libs/Widgets/ctkThumbnailLabel.cpp
@@ -45,6 +45,7 @@ class ctkThumbnailLabelPrivate: public Ui_ctkThumbnailLabel
 
   // Constructor
   ctkThumbnailLabelPrivate(ctkThumbnailLabel* parent);
+  virtual ~ctkThumbnailLabelPrivate();
 
   virtual void setupUi(QWidget* widget);
 
@@ -74,6 +75,11 @@ ctkThumbnailLabelPrivate::ctkThumbnailLabelPrivate(ctkThumbnailLabel* parent)
   this->TransformationMode = Qt::FastTransformation;
 }
 
+//----------------------------------------------------------------------------
+ctkThumbnailLabelPrivate::~ctkThumbnailLabelPrivate()
+{
+}
+
 //----------------------------------------------------------------------------
 void ctkThumbnailLabelPrivate::setupUi(QWidget* widget)
 {

From cc003ae7fd922d44091e501a811a29924ecdc4c0 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Tue, 24 Jul 2012 05:29:37 -0400
Subject: [PATCH 070/247] Fix sign-promo warning in ctkCommandLineParserTest1

See issue #212
---
 Libs/Core/Testing/Cpp/ctkCommandLineParserTest1.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Libs/Core/Testing/Cpp/ctkCommandLineParserTest1.cpp b/Libs/Core/Testing/Cpp/ctkCommandLineParserTest1.cpp
index b2b0e63163..d4173509a0 100644
--- a/Libs/Core/Testing/Cpp/ctkCommandLineParserTest1.cpp
+++ b/Libs/Core/Testing/Cpp/ctkCommandLineParserTest1.cpp
@@ -597,7 +597,9 @@ int ctkCommandLineParserTest1(int, char*[])
   //  Check that QSettings worked
   if(settings.status() != QSettings::NoError)
   {
-    qCritical() << "QSettings tests setup - QSettings::status() returned " << settings.status() << ".";
+    qCritical() << "QSettings tests setup - QSettings::status() returned "
+                << static_cast(settings.status()) << ".";
+    return EXIT_FAILURE;
     return EXIT_FAILURE;
   }
 

From c9db9670eccf79826422cf0a7f4913a6ae5ed8dc Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Tue, 24 Jul 2012 05:31:33 -0400
Subject: [PATCH 071/247] Fix unused warning in
 ctkTransferFunctionRepresentation

See issue #213
---
 Libs/Core/ctkTransferFunctionRepresentation.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Libs/Core/ctkTransferFunctionRepresentation.cpp b/Libs/Core/ctkTransferFunctionRepresentation.cpp
index 2fee8b98bb..45f78b6269 100644
--- a/Libs/Core/ctkTransferFunctionRepresentation.cpp
+++ b/Libs/Core/ctkTransferFunctionRepresentation.cpp
@@ -248,7 +248,6 @@ void ctkTransferFunctionRepresentation::computeCurve()
     else //dynamic_cast(startCP))
       {
       QList points = this->bezierParams(startCP, nextCP);
-      QList::iterator it = points.begin();
       QList bezierPoints;
       foreach(const ctkPoint& p, points)
         {
@@ -331,7 +330,6 @@ void ctkTransferFunctionRepresentation::computeGradient()
     else //dynamic_cast(startCP))
       { // TODO handle bezier points with color
       QList points = this->bezierParams(startCP, nextCP);
-      QList::iterator it = points.begin();
       QList bezierPoints;
       foreach(const ctkPoint& p, points)
         {

From 550ddccc2c4ceef99e1ecb544b62a06cedbf0752 Mon Sep 17 00:00:00 2001
From: Jean-Christophe Fillion-Robin 
Date: Tue, 24 Jul 2012 05:35:41 -0400
Subject: [PATCH 072/247] Fix unused variable warning in ctkDirectoryButton.cpp

See issue #214
---
 Libs/Widgets/ctkDirectoryButton.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Libs/Widgets/ctkDirectoryButton.cpp b/Libs/Widgets/ctkDirectoryButton.cpp
index 18f387d546..64a46d05b9 100644
--- a/Libs/Widgets/ctkDirectoryButton.cpp
+++ b/Libs/Widgets/ctkDirectoryButton.cpp
@@ -81,7 +81,6 @@ void ctkDirectoryButtonPrivate::init()
 //-----------------------------------------------------------------------------
 void ctkDirectoryButtonPrivate::updateDisplayText()
 {
-  Q_Q(ctkDirectoryButton);
   QString buttonText = this->DisplayText;
   if (buttonText.isNull())
     {

From d681005124150e0bbc6012750487160ee3e15342 Mon Sep 17 00:00:00 2001
From: Andras Lasso 
Date: Tue, 24 Jul 2012 20:13:58 -0400
Subject: [PATCH 073/247] Fixed minor DICOM import related issues

---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 14 ++++++++++----
 Libs/DICOM/Core/ctkDICOMDataset.cpp  |  3 +--
 Libs/DICOM/Core/ctkDICOMModel.cpp    |  2 +-
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index aec9b99908..aca1041d59 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -848,7 +848,7 @@ int ctkDICOMDatabasePrivate::insertPatient(const ctkDICOMDataset& ctkDataset)
       insertPatientStatement.prepare ( "INSERT INTO Patients ('UID', 'PatientsName', 'PatientID', 'PatientsBirthDate', 'PatientsBirthTime', 'PatientsSex', 'PatientsAge', 'PatientsComments' ) values ( NULL, ?, ?, ?, ?, ?, ?, ? )" );
       insertPatientStatement.bindValue ( 0, patientsName );
       insertPatientStatement.bindValue ( 1, patientID );
-      insertPatientStatement.bindValue ( 2, patientsBirthDate );
+      insertPatientStatement.bindValue ( 2, QDate::fromString ( patientsBirthDate, "yyyyMMdd" ) );
       insertPatientStatement.bindValue ( 3, patientsBirthTime );
       insertPatientStatement.bindValue ( 4, patientsSex );
       // TODO: shift patient's age to study,
@@ -944,8 +944,8 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS
       insertSeriesStatement.bindValue ( 0, seriesInstanceUID );
       insertSeriesStatement.bindValue ( 1, studyInstanceUID );
       insertSeriesStatement.bindValue ( 2, static_cast(seriesNumber) );
-      insertSeriesStatement.bindValue ( 3, seriesDate );
-      insertSeriesStatement.bindValue ( 4, QDate::fromString ( seriesTime, "yyyyMMdd" ) );
+      insertSeriesStatement.bindValue ( 3, QDate::fromString ( seriesDate, "yyyyMMdd" ) );
+      insertSeriesStatement.bindValue ( 4, seriesTime );
       insertSeriesStatement.bindValue ( 5, seriesDescription );
       insertSeriesStatement.bindValue ( 6, modality );
       insertSeriesStatement.bindValue ( 7, bodyPartExamined );
@@ -1024,6 +1024,12 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
   QString studyInstanceUID(ctkDataset.GetElementAsString(DCM_StudyInstanceUID) );
   QString seriesInstanceUID(ctkDataset.GetElementAsString(DCM_SeriesInstanceUID) );
   QString patientID(ctkDataset.GetElementAsString(DCM_PatientID) );
+  if ( patientID.isEmpty() && !studyInstanceUID.isEmpty() ) 	 
+  { // Use study instance uid as patient id if patient id is empty - can happen on anonymized datasets
+    // see: http://www.na-mic.org/Bug/view.php?id=2040
+    logger.warn("Petient ID is empty, using studyInstanceUID as patient ID");
+    patientID = studyInstanceUID;
+  }
   if ( patientsName.isEmpty() && !patientID.isEmpty() )
     { // Use patient id as name if name is empty - can happen on anonymized datasets
       // see: http://www.na-mic.org/Bug/view.php?id=1643
@@ -1031,7 +1037,7 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
     }
   if ( patientsName.isEmpty() || studyInstanceUID.isEmpty() || patientID.isEmpty() )
     {
-      logger.error("Dataset is missing necessary information!");
+      logger.error("Dataset is missing necessary information (patient name, study instance UID, or patient ID)!");
       return;
     }
 
diff --git a/Libs/DICOM/Core/ctkDICOMDataset.cpp b/Libs/DICOM/Core/ctkDICOMDataset.cpp
index 81136f55a3..6a243fa4dc 100644
--- a/Libs/DICOM/Core/ctkDICOMDataset.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDataset.cpp
@@ -112,11 +112,10 @@ void ctkDICOMDataset::InitializeFromFile(const QString& filename,
                                          const Uint32 maxReadLength,
                                          const E_FileReadMode readMode)
 {
-  Q_UNUSED(maxReadLength);
   DcmDataset *dataset;
 
   DcmFileFormat fileformat;
-  OFCondition status = fileformat.loadFile(filename.toAscii().data(), readXfer, groupLength, readMode);
+  OFCondition status = fileformat.loadFile(filename.toAscii().data(), readXfer, groupLength, maxReadLength, readMode);
   dataset = fileformat.getAndRemoveDataset();
 
   if (!status.good())
diff --git a/Libs/DICOM/Core/ctkDICOMModel.cpp b/Libs/DICOM/Core/ctkDICOMModel.cpp
index 59d640c99c..728d205bd4 100644
--- a/Libs/DICOM/Core/ctkDICOMModel.cpp
+++ b/Libs/DICOM/Core/ctkDICOMModel.cpp
@@ -335,7 +335,7 @@ void ctkDICOMModelPrivate::updateQueries(Node* node)const
           condition.append(" ( StudyDate BETWEEN \'" + QDate::fromString(this->SearchParameters["StartDate"].toString(), "yyyyMMdd").toString("yyyy-MM-dd")
                            + "\' AND \'" + QDate::fromString(this->SearchParameters["EndDate"].toString(), "yyyyMMdd").toString("yyyy-MM-dd") + "\' ) AND ");
         }
-      query = this->generateQuery("StudyInstanceUID as UID, StudyDescription as Name, ModalitiesInStudy as Scan, StudyDate as Date, AccessionNumber as Number, ReferringPhysician as Institution, ReferringPhysician as Referrer, PerformingPhysiciansName as Performer", "Studies", condition + QString("PatientsUID='%1'").arg(node->UID));
+      query = this->generateQuery("StudyInstanceUID as UID, StudyDescription as Name, ModalitiesInStudy as Scan, StudyDate as Date, AccessionNumber as Number, InstitutionName as Institution, ReferringPhysician as Referrer, PerformingPhysiciansName as Performer", "Studies", condition + QString("PatientsUID='%1'").arg(node->UID));
       logger.debug ( "ctkDICOMModelPrivate::updateQueries for Patient: query is: " + query );
       break;
     case ctkDICOMModel::StudyType:

From 118ba91bf2b67586baa63a06a235681fd6512e18 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Wed, 25 Jul 2012 07:57:16 -0400
Subject: [PATCH 074/247] Fix typo in log message

Per comment from Jc

https://github.com/lassoan/CTK/commit/d681005124150e0bbc6012750487160ee3e15342
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index aca1041d59..47f3fc11ac 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -1027,7 +1027,7 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
   if ( patientID.isEmpty() && !studyInstanceUID.isEmpty() ) 	 
   { // Use study instance uid as patient id if patient id is empty - can happen on anonymized datasets
     // see: http://www.na-mic.org/Bug/view.php?id=2040
-    logger.warn("Petient ID is empty, using studyInstanceUID as patient ID");
+    logger.warn("Patient ID is empty, using studyInstanceUID as patient ID");
     patientID = studyInstanceUID;
   }
   if ( patientsName.isEmpty() && !patientID.isEmpty() )

From b023d87b67fbb29180a6555290edf903c92f8d43 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Wed, 25 Jul 2012 17:16:56 +0200
Subject: [PATCH 075/247] Add the path to the Qt designer plugins to the ui
 loader.

---
 Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
index cdf7abb54e..6cffd919e1 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -55,6 +56,13 @@ QObject* ctkCmdLineModuleQtGui::guiHandle() const
   }
 
   QUiLoader uiLoader;
+#ifdef CMAKE_INTDIR
+  QString appPath = QCoreApplication::applicationDirPath();
+  if (appPath.endsWith(CMAKE_INTDIR))
+  {
+    uiLoader.addPluginPath(appPath + "/../designer");
+  }
+#endif
   WidgetTree = uiLoader.load(&uiForm);
   return WidgetTree;
 }

From da9b93bfda8be6d705045fc9124d62647120ae65 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Wed, 25 Jul 2012 17:18:53 +0200
Subject: [PATCH 076/247] Enable needed dependencies for
 ctkCommandLineModuleExplorer.

---
 CMakeLists.txt | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a7cc780b65..f2d142aed6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -509,7 +509,22 @@ ctk_app_option(ctkEventBusDemo
 ctk_app_option(ctkCommandLineModuleExplorer
                "Build the Command Line Module Explorer" OFF
                CTK_BUILD_EXAMPLES)
-               
+
+# We use the CTKWidgets library together with the Qt Designer plug-in
+# in ctkCommandLineModuleExplorer, so enabling the options here.
+# (We do not need to link them into the executable, hence no entries
+# in target_libraries.cmake)
+
+if(CTK_APP_ctkCommandLineModuleExplorer)
+  foreach(_option CTK_LIB_Widgets CTK_BUILD_QTDESIGNER_PLUGINS)
+    if(NOT ${_option})
+      get_property(_docstring CACHE ${_option} PROPERTY HELPSTRING)
+      set(${_option} ON CACHE BOOL "${_docstring}" FORCE)
+      message("Enabling option [${_option}] required by [ctkCommandLineModuleExplorer]")
+    endif()
+  endforeach()
+endif()
+
 ctk_app_option(ctkPluginBrowser
                "Build the DICOM example application" OFF
                CTK_ENABLE_PluginFramework AND CTK_BUILD_EXAMPLES)

From be8e8768cc32cb0cb19bced9e4cedc710cca45d9 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 26 Jul 2012 15:13:14 +0200
Subject: [PATCH 077/247] Use inheritance for the custom QFuture class.

---
 .../Core/ctkCmdLineModule.h                   |   3 +-
 .../Core/ctkCmdLineModuleFuture.h             | 137 ++----------------
 .../Core/ctkCmdLineModuleFutureInterface.h    |   2 +-
 3 files changed, 13 insertions(+), 129 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.h b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
index 65c516da8c..c090ba6a81 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
@@ -27,10 +27,9 @@
 #include 
 
 template class QHash;
-template class QFuture;
 
 class ctkCmdLineModuleResult;
-typedef QFuture ctkCmdLineModuleFuture;
+class ctkCmdLineModuleFuture;
 class ctkCmdLineModuleReference;
 class ctkCmdLineModulePrivate;
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
index b6f9fb3c16..a3bde956de 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
@@ -24,146 +24,31 @@
 
 #include "ctkCmdLineModuleFutureInterface.h"
 
-#include 
-#include 
 #include 
 
-template 
-class QFutureWatcher;
-template <>
-class QFutureWatcher;
-
 /**
- * QFuture specialization with two additional methods:
+ * QFuture sub-class with two additional methods:
  *
  *   - bool canCancel()
  *   - bool canPause()
  */
-template<>
-class QFuture
+class ctkCmdLineModuleFuture : public QFuture
 {
 public:
 
-  QFuture()
-    : d(QFutureInterface::canceledResult())
-  { }
-  explicit QFuture(QFutureInterface *p) // internal
-    : d(*p)
-  { }
-  QFuture(const QFuture &other)
-    : d(other.d)
-  { }
-  ~QFuture()
-  { }
-
-  inline QFuture &operator=(const QFuture &other);
-  bool operator==(const QFuture &other) const { return (d == other.d); }
-  bool operator!=(const QFuture &other) const { return (d != other.d); }
-
-  // additional methods
-  bool canCancel() const { return  d.canCancel(); }
-  bool canPause() const { return d.canPause(); }
-
-  void cancel() { d.cancel(); }
-  bool isCanceled() const { return d.isCanceled(); }
-
-  void setPaused(bool paused) { d.setPaused(paused); }
-  bool isPaused() const { return d.isPaused(); }
-  void pause() { setPaused(true); }
-  void resume() { setPaused(false); }
-  void togglePaused() { d.togglePaused(); }
-
-  bool isStarted() const { return d.isStarted(); }
-  bool isFinished() const { return d.isFinished(); }
-  bool isRunning() const { return d.isRunning(); }
-
-  int resultCount() const { return d.resultCount(); }
-  int progressValue() const { return d.progressValue(); }
-  int progressMinimum() const { return d.progressMinimum(); }
-  int progressMaximum() const { return d.progressMaximum(); }
-  QString progressText() const { return d.progressText(); }
-  void waitForFinished() { d.waitForFinished(); }
-
-  inline ctkCmdLineModuleResult result() const;
-  inline ctkCmdLineModuleResult resultAt(int index) const;
-  bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); }
-
-  operator ctkCmdLineModuleResult() const { return result(); }
-  QList results() const { return d.results(); }
-
-  class const_iterator
+  ctkCmdLineModuleFuture()
   {
-  public:
-    typedef std::bidirectional_iterator_tag iterator_category;
-    typedef qptrdiff difference_type;
-    typedef ctkCmdLineModuleResult value_type;
-    typedef const ctkCmdLineModuleResult *pointer;
-    typedef const ctkCmdLineModuleResult &reference;
-
-    inline const_iterator() {}
-    inline const_iterator(QFuture const * const _future, int _index) : future(_future), index(_index) {}
-    inline const_iterator(const const_iterator &o) : future(o.future), index(o.index)  {}
-    inline const_iterator &operator=(const const_iterator &o)
-    { future = o.future; index = o.index; return *this; }
-    inline const ctkCmdLineModuleResult &operator*() const { return future->d.resultReference(index); }
-    inline const ctkCmdLineModuleResult *operator->() const { return future->d.resultPointer(index); }
-
-    inline bool operator!=(const const_iterator &other) const
-    {
-      if (index == -1 && other.index == -1) // comparing end != end?
-        return false;
-      if (other.index == -1)
-        return (future->isRunning() || (index < future->resultCount()));
-      return (index != other.index);
-    }
-
-    inline bool operator==(const const_iterator &o) const { return !operator!=(o); }
-    inline const_iterator &operator++() { ++index; return *this; }
-    inline const_iterator operator++(int) { const_iterator r = *this; ++index; return r; }
-    inline const_iterator &operator--() { --index; return *this; }
-    inline const_iterator operator--(int) { const_iterator r = *this; --index; return r; }
-    inline const_iterator operator+(int j) const { return const_iterator(future, index + j); }
-    inline const_iterator operator-(int j) const { return const_iterator(future, index - j); }
-    inline const_iterator &operator+=(int j) { index += j; return *this; }
-    inline const_iterator &operator-=(int j) { index -= j; return *this; }
-  private:
-    QFuture const * future;
-    int index;
-  };
-  friend class const_iterator;
-  typedef const_iterator ConstIterator;
-
-  const_iterator begin() const { return  const_iterator(this, 0); }
-  const_iterator constBegin() const { return  const_iterator(this, 0); }
-  const_iterator end() const { return const_iterator(this, -1); }
-  const_iterator constEnd() const { return const_iterator(this, -1); }
-
-private:
-  friend class QFutureWatcher;
-
-public: // Warning: the d pointer is not documented and is considered private.
-  mutable QFutureInterface d;
-};
+  }
 
-typedef QFuture ctkCmdLineModuleFuture;
-
-inline ctkCmdLineModuleFuture& ctkCmdLineModuleFuture::operator=(const ctkCmdLineModuleFuture& other)
-{
-  d = other.d;
-  return *this;
-}
+  explicit ctkCmdLineModuleFuture(ctkCmdLineModuleFutureInterface* p) // internal
+    : QFuture(p)
+  {
+  }
 
-inline ctkCmdLineModuleResult ctkCmdLineModuleFuture::result() const
-{
-  d.waitForResult(0);
-  return d.resultReference(0);
-}
+  bool canCancel() const { return  d.canCancel(); }
+  bool canPause() const { return d.canPause(); }
 
-inline ctkCmdLineModuleResult ctkCmdLineModuleFuture::resultAt(int index) const
-{
-  d.waitForResult(index);
-  return d.resultReference(index);
-}
+};
 
 inline ctkCmdLineModuleFuture ctkCmdLineModuleFutureInterface::future()
 {
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
index 1ab8af8f1e..e65fce7b4e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
@@ -26,7 +26,7 @@
 
 #include 
 
-typedef QFuture ctkCmdLineModuleFuture;
+class ctkCmdLineModuleFuture;
 
 template <>
 class QFutureInterface : public QFutureInterfaceBase

From 048555a14dd9267c04de726f2ac978713b8607c3 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 26 Jul 2012 15:13:41 +0200
Subject: [PATCH 078/247] Added cancel support when running modules.

---
 .../ctkCLModuleExplorerMainWindow.cpp         |  16 +--
 .../Cpp/ctkCmdLineModuleFutureTest.cpp        | 105 +++++++++++++++---
 .../TestBed/ctkCmdLineModuleTestBed.cpp       |  12 +-
 .../TestBed/ctkCmdLineModuleTestBed.xml       |  14 +--
 .../Core/ctkCmdLineModuleProcessTask.cpp      |  38 +++++--
 .../Core/ctkCmdLineModuleProcessTask.h        |   8 +-
 6 files changed, 145 insertions(+), 48 deletions(-)

diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
index 7d1edb76f5..55f65f24c9 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
@@ -91,14 +91,14 @@ void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
   ctkCmdLineModuleFuture future = module->run();
   watcher->setFuture(future);
 
-  try
-  {
-    future.waitForFinished();
-  }
-  catch (const ctkException& e)
-  {
-    qDebug() << e.printStackTrace();
-  }
+//  try
+//  {
+//    future.waitForFinished();
+//  }
+//  catch (const ctkException& e)
+//  {
+//    qDebug() << e.printStackTrace();
+//  }
 }
 
 void ctkCLModuleExplorerMainWindow::moduleStarted()
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
index 20f09318ac..8eab70999c 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
@@ -86,10 +86,19 @@ bool futureTestStartFinish(ctkCmdLineModule* module)
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
+  qDebug() << module->commandLineArguments();
   ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
 
-  future.waitForFinished();
+  try
+  {
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
 
   // process pending events
   QCoreApplication::processEvents();
@@ -128,11 +137,19 @@ bool futureTestProgress(ctkCmdLineModule* module)
   QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
-  module->setValue("fileVar", "output1");
+  module->setValue("numOutputsVar", 1);
   ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
 
-  future.waitForFinished();
+  try
+  {
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
 
   // process pending events
   QCoreApplication::processEvents();
@@ -140,6 +157,54 @@ bool futureTestProgress(ctkCmdLineModule* module)
   return signalTester.checkSignals(expectedSignals);
 }
 
+bool futureTestPauseAndCancel(ctkCmdLineModule* module)
+{
+  qDebug() << "Testing ctkCmdLineModuleFuture pause and cancel capabilities";
+
+  QList expectedSignals;
+  expectedSignals.push_back("module.started");
+  expectedSignals.push_back("module.finished");
+
+  ctkCmdLineModuleSignalTester signalTester;
+
+  QFutureWatcher watcher;
+  QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
+  QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &signalTester, SLOT(moduleProgressValueChanged(int)));
+  QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
+  QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
+
+  module->setValue("runtimeVar", 60);
+  ctkCmdLineModuleFuture future = module->run();
+  watcher.setFuture(future);
+
+
+  try
+  {
+    future.cancel();
+    future.waitForFinished();
+  }
+  catch (const ctkCmdLineModuleRunException& e)
+  {
+    qDebug() << e;
+    return false;
+  }
+
+  // process pending events
+  QCoreApplication::processEvents();
+
+  if (!signalTester.checkSignals(expectedSignals))
+  {
+    return false;
+  }
+
+  if (!(future.isCanceled() && future.isFinished()))
+  {
+    qDebug() << "Cancel state wrong";
+    return false;
+  }
+  return true;
+}
+
 bool futureTestError(ctkCmdLineModule* module)
 {
   qDebug() << "Testing ctkCmdLineModuleFuture error reporting.";
@@ -183,27 +248,37 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[])
     qCritical() << "Module at" << moduleFilename << "could not be registered";
   }
 
-  QScopedPointer module(manager.createModule(moduleRef));
-
-  if (!futureTestStartFinish(module.data()))
   {
-    return EXIT_FAILURE;
+    QScopedPointer module(manager.createModule(moduleRef));
+    if (!futureTestStartFinish(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
 
-  if (!futureTestProgress(module.data()))
   {
-    return EXIT_FAILURE;
+    QScopedPointer module(manager.createModule(moduleRef));
+    if (!futureTestProgress(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
 
-  if (!futureTestError(module.data()))
   {
-    return EXIT_FAILURE;
+    QScopedPointer module(manager.createModule(moduleRef));
+    if (!futureTestError(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
   }
 
-//  if (!futureTestPauseAndCancel(module.data()))
-//  {
-//    return EXIT_FAILURE;
-//  }
+  {
+    QScopedPointer module(manager.createModule(moduleRef));
+    if (!futureTestPauseAndCancel(module.data()))
+    {
+      return EXIT_FAILURE;
+    }
+  }
 
   //  if (!futureTestResultReady(module.data()))
   //  {
diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
index 03fdd86f1d..86ae70ef4d 100644
--- a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
@@ -45,6 +45,7 @@ int main(int argc, char* argv[])
   parser.addArgument("help", "h", QVariant::Bool, "Show this help text");
   parser.addArgument("xml", "", QVariant::Bool, "Print a XML description of this modules command line interface");
   parser.addArgument("runtime", "", QVariant::Int, "Runtime in seconds", 1);
+  parser.addArgument("numOutputs", "", QVariant::Int, "Number of outpusts", 0);
   parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0);
   parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false);
   parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0);
@@ -65,10 +66,6 @@ int main(int argc, char* argv[])
   if (parsedArgs.contains("help") || parsedArgs.contains("h"))
   {
     out << parser.helpText();
-    out.setFieldWidth(parser.fieldWidth());
-    out.setFieldAlignment(QTextStream::AlignLeft);
-    out << "  ...";
-    out << "One or more output strings\n";
     return EXIT_SUCCESS;
   }
 
@@ -83,13 +80,18 @@ int main(int argc, char* argv[])
   // Do something
 
   float runtime = parsedArgs["runtime"].toFloat();
+  int numOutputs = parsedArgs["numOutputs"].toInt();
   float exitTime = parsedArgs["exitTime"].toFloat();
   int exitTimeMillis = static_cast(exitTime/2.0 * 1000.0);
   int exitCode = parsedArgs["exitCode"].toInt();
   bool exitCrash = parsedArgs["exitCrash"].toBool();
   QString errorText = parsedArgs["errorText"].toString();
 
-  QStringList outputs = parser.unparsedArguments();
+  QStringList outputs;
+  for (int i = 0; i < numOutputs; ++i)
+  {
+    outputs << "Output " + QString::number(i+1);
+  }
 
   if (outputs.empty())
   {
diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
index a21060693a..08e0a4a5b7 100644
--- a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
+++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml
@@ -25,13 +25,13 @@ Configurable behaviour for testing purposes.
         1
       
     
-    
-      fileVar
-      0
-      Output files which will be reported as the progress text via a QFutureWatcher.
-      
-      output
-    
+    
+      numOutputsVar
+      numOutputs
+      Number of outputs which will be reported as the progress text via a QFutureWatcher.
+      
+      0
+    
     
       exitTimeVar
       exitTime
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
index 38d9adea46..46c45c5e5e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
@@ -81,7 +81,7 @@ int ctkCmdLineModuleProcessProgressWatcher::incrementProgress()
 }
 
 ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
-  : location(location), args(args)
+  : process(NULL), location(location), args(args)
 {
   this->setCanCancel(true);
 }
@@ -107,32 +107,46 @@ void ctkCmdLineModuleProcessTask::run()
     return;
   }
 
-  QProcess process;
-  process.setReadChannel(QProcess::StandardOutput);
+  process = new QProcess();
+  process->setReadChannel(QProcess::StandardOutput);
 
   QEventLoop localLoop;
-  QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
-  QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
+  QObject::connect(process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
+  QObject::connect(process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
 
-  process.start(location, args);
+  QTimer pollCancelTimer;
+  pollCancelTimer.setInterval(500);
+  this->connect(&pollCancelTimer, SIGNAL(timeout()), SLOT(pollCancelState()));
 
-  ctkCmdLineModuleProcessProgressWatcher progressWatcher(process, location, *this);
+  process->start(location, args);
+
+  ctkCmdLineModuleProcessProgressWatcher progressWatcher(*process, location, *this);
   Q_UNUSED(progressWatcher)
 
   localLoop.exec();
 
-  if (process.error() != QProcess::UnknownError)
+  if (process->error() != QProcess::UnknownError)
   {
-    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString()));
+    this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->errorString()));
   }
-  else if (process.exitCode() != 0)
+  else if (process->exitCode() != 0)
   {
-    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.readAllStandardError()));
+    this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->readAllStandardError()));
   }
 
-  this->setProgressValueAndText(1000, process.readAllStandardError());
+  this->setProgressValueAndText(1000, process->readAllStandardError());
 
   //this->reportResult(result);
   this->reportFinished();
 
+  delete process;
+
+}
+
+void ctkCmdLineModuleProcessTask::pollCancelState()
+{
+  if (this->isCanceled() && process->state() == QProcess::Running)
+  {
+    process->terminate();
+  }
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
index 1e4dd8c252..b1d9e0cb69 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
@@ -32,8 +32,9 @@
 
 class QProcess;
 
-class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable
+class ctkCmdLineModuleProcessTask : public QObject, public ctkCmdLineModuleFutureInterface, public QRunnable
 {
+  Q_OBJECT
 
 public:
 
@@ -44,8 +45,13 @@ class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, publ
 
   void run();
 
+protected Q_SLOTS:
+
+  void pollCancelState();
+
 private:
 
+  QProcess* process;
   const QString location;
   const QStringList args;
 

From d7563dd526dbb8017a3469e6b8b8bf776dc2e9b4 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Fri, 27 Jul 2012 09:35:30 +0200
Subject: [PATCH 079/247] Cancel and pause (on POSIX systems) support for a
 process-based QFuture.

---
 .../Cpp/ctkCmdLineModuleFutureTest.cpp        |  46 ++++++-
 .../Cpp/ctkCmdLineModuleSignalTester.cpp      |  15 +++
 .../Cpp/ctkCmdLineModuleSignalTester.h        |   4 +
 .../TestBed/ctkCmdLineModuleTestBed.cpp       |  42 +++----
 .../Core/ctkCmdLineModuleFutureInterface.h    |   4 +-
 .../Core/ctkCmdLineModuleProcessTask.cpp      | 114 ++++++++++++------
 .../Core/ctkCmdLineModuleProcessTask.h        |  23 ++--
 7 files changed, 173 insertions(+), 75 deletions(-)

diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
index 8eab70999c..1cd7d3ce8c 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp
@@ -161,26 +161,62 @@ bool futureTestPauseAndCancel(ctkCmdLineModule* module)
 {
   qDebug() << "Testing ctkCmdLineModuleFuture pause and cancel capabilities";
 
-  QList expectedSignals;
-  expectedSignals.push_back("module.started");
-  expectedSignals.push_back("module.finished");
 
   ctkCmdLineModuleSignalTester signalTester;
 
   QFutureWatcher watcher;
   QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted()));
-  QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &signalTester, SLOT(moduleProgressValueChanged(int)));
-  QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString)));
+  QObject::connect(&watcher, SIGNAL(paused()), &signalTester, SLOT(modulePaused()));
+  QObject::connect(&watcher, SIGNAL(resumed()), &signalTester, SLOT(moduleResumed()));
+  QObject::connect(&watcher, SIGNAL(canceled()), &signalTester, SLOT(moduleCanceled()));
   QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished()));
 
   module->setValue("runtimeVar", 60);
+  qDebug() << module->commandLineArguments();
   ctkCmdLineModuleFuture future = module->run();
   watcher.setFuture(future);
 
+  QList expectedSignals;
+  expectedSignals.push_back("module.started");
+  if (future.canPause())
+  {
+    // Due to Qt bug 12152, these two signals are reversed
+    expectedSignals.push_back("module.resumed");
+    expectedSignals.push_back("module.paused");
+  }
+  if (future.canCancel())
+  {
+    expectedSignals.push_back("module.canceled");
+  }
+  expectedSignals.push_back("module.finished");
+
+  sleep(1);
+
+  QCoreApplication::processEvents();
+  future.pause();
+  sleep(1);
+  QCoreApplication::processEvents();
+
+  if (future.canPause())
+  {
+    if (!(future.isPaused() && future.isRunning()))
+    {
+      qDebug() << "Pause state wrong";
+      future.setPaused(false);
+      future.cancel();
+      QCoreApplication::processEvents();
+      future.waitForFinished();
+      return false;
+    }
+  }
+
+  future.togglePaused();
+  QCoreApplication::processEvents();
 
   try
   {
     future.cancel();
+    QCoreApplication::processEvents();
     future.waitForFinished();
   }
   catch (const ctkCmdLineModuleRunException& e)
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
index 93447c978b..c8addc1ea0 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
@@ -43,6 +43,21 @@ void ctkCmdLineModuleSignalTester::moduleProgressTextChanged(const QString &/*te
   events.push_back("module.progressTextChanged");
 }
 
+void ctkCmdLineModuleSignalTester::modulePaused()
+{
+  events.push_back("module.paused");
+}
+
+void ctkCmdLineModuleSignalTester::moduleResumed()
+{
+  events.push_back("module.resumed");
+}
+
+void ctkCmdLineModuleSignalTester::moduleCanceled()
+{
+  events.push_back("module.canceled");
+}
+
 void ctkCmdLineModuleSignalTester::filterStarted(const QString &/*name*/, const QString &/*comment*/)
 {
   events.push_back("filter.started");
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
index 82d764bb08..eb3365c84c 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleSignalTester.h
@@ -42,6 +42,10 @@ public Q_SLOTS:
   virtual void moduleProgressValueChanged(int progress);
   virtual void moduleProgressTextChanged(const QString& text);
 
+  virtual void modulePaused();
+  virtual void moduleResumed();
+  virtual void moduleCanceled();
+
   virtual void filterStarted(const QString& name, const QString& comment);
   virtual void filterProgress(float progress);
   virtual void filterFinished(const QString& name);
diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
index 86ae70ef4d..6e1dae8314 100644
--- a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp
@@ -93,32 +93,24 @@ int main(int argc, char* argv[])
     outputs << "Output " + QString::number(i+1);
   }
 
-  if (outputs.empty())
-  {
-    // no outputs given, just return
-    if (exitCrash)
-    {
-      int* crash = 0;
-      *crash = 5;
-    }
-    if (exitCode != 0)
-    {
-      err << errorText;
-    }
-    return exitCode;
-  }
-
-  float stepTime = runtime / static_cast(outputs.size());
+  float stepTime = outputs.size() ? runtime / static_cast(outputs.size()) : runtime;
 
   QTime time;
   time.start();
 
   struct timespec nanostep;
 
-  out << "\n";
-  out << "Test Filter\n";
-  out << "Does nothing useful\n";
-  out << "\n";
+  if (!outputs.empty())
+  {
+    out << "\n";
+    out << "Test Filter\n";
+    out << "Does nothing useful\n";
+    out << "\n";
+  }
+  else
+  {
+    outputs.push_back("dummy");
+  }
 
   float progressStep = 1.0f / static_cast(outputs.size());
   for(int i = 0; i < outputs.size(); ++i)
@@ -146,10 +138,12 @@ int main(int argc, char* argv[])
     nanosleep(&nanostep, NULL);
 
     // print the first output
-    out << output; endl(out);
-
-    // report progress
-    out << "" << (i+1)*progressStep << "\n";
+    if (output != "dummy")
+    {
+      out << output; endl(out);
+      // report progress
+      out << "" << (i+1)*progressStep << "\n";
+    }
   }
 
   // sleep 1 second to avoid squashing the last progress event with the finished event
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
index e65fce7b4e..9096f94c60 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h
@@ -41,7 +41,7 @@ class QFutureInterface : public QFutureInterfaceBase
 
   QFutureInterface(const QFutureInterface &other)
     : QFutureInterfaceBase(other),
-      CanCancel(false), CanPause(false)
+      CanCancel(other.CanCancel), CanPause(other.CanPause)
   { }
 
   ~QFutureInterface()
@@ -58,6 +58,8 @@ class QFutureInterface : public QFutureInterfaceBase
     if (referenceCountIsOne())
       resultStore().clear();
     QFutureInterfaceBase::operator=(other);
+    CanCancel = other.CanCancel;
+    CanPause = other.CanPause;
     return *this;
   }
 
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
index 46c45c5e5e..9bc2e03c58 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp
@@ -29,10 +29,14 @@
 #include 
 #include 
 
-ctkCmdLineModuleProcessProgressWatcher::ctkCmdLineModuleProcessProgressWatcher(QProcess& process, const QString& location,
-                                                                               ctkCmdLineModuleFutureInterface &futureInterface)
+#ifdef Q_OS_UNIX
+#include 
+#endif
+
+ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location,
+                                                               ctkCmdLineModuleFutureInterface &futureInterface)
   : process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process),
-    progressValue(0)
+    processPaused(false), progressValue(0)
 {
   futureInterface.setProgressRange(0, 1000);
 
@@ -40,30 +44,81 @@ ctkCmdLineModuleProcessProgressWatcher::ctkCmdLineModuleProcessProgressWatcher(Q
   connect(&processXmlWatcher, SIGNAL(filterProgress(float)), SLOT(filterProgress(float)));
   connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString)));
   connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString)));
+
+  connect(&futureWatcher, SIGNAL(canceled()), SLOT(cancelProcess()));
+#ifdef Q_OS_UNIX
+  connect(&futureWatcher, SIGNAL(resumed()), SLOT(resumeProcess()));
+  // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is
+  // not emitted directly when the QFuture is paused. Instead, it is emitted after
+  // resuming the future, after the "resume" signal has been emitted...
+  //connect(&futureWatcher, SIGNAL(paused()), SLOT(pauseProcess()));
+  connect(&pollPauseTimer, SIGNAL(timeout()), this, SLOT(pauseProcess()));
+  pollPauseTimer.start(500);
+#endif
+  futureWatcher.setFuture(futureInterface.future());
 }
 
-void ctkCmdLineModuleProcessProgressWatcher::filterStarted(const QString& name, const QString& comment)
+void ctkCmdLineModuleProcessWatcher::filterStarted(const QString& name, const QString& comment)
 {
   Q_UNUSED(comment)
   futureInterface.setProgressValueAndText(incrementProgress(), name);
 }
 
-void ctkCmdLineModuleProcessProgressWatcher::filterProgress(float progress)
+void ctkCmdLineModuleProcessWatcher::filterProgress(float progress)
 {
   futureInterface.setProgressValue(updateProgress(progress));
 }
 
-void ctkCmdLineModuleProcessProgressWatcher::filterFinished(const QString& name)
+void ctkCmdLineModuleProcessWatcher::filterFinished(const QString& name)
 {
   futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name);
 }
 
-void ctkCmdLineModuleProcessProgressWatcher::filterXmlError(const QString &error)
+void ctkCmdLineModuleProcessWatcher::filterXmlError(const QString &error)
 {
   qDebug().nospace() << "[Module " << location << "]: " << error;
 }
 
-int ctkCmdLineModuleProcessProgressWatcher::updateProgress(float progress)
+void ctkCmdLineModuleProcessWatcher::pauseProcess()
+{
+  if (processPaused || !futureInterface.isPaused()) return;
+
+#ifdef Q_OS_UNIX
+  if (::kill(process.pid(), SIGSTOP))
+  {
+    // error
+    futureInterface.setPaused(false);
+  }
+  else
+  {
+    processPaused = true;
+  }
+#endif
+}
+
+void ctkCmdLineModuleProcessWatcher::resumeProcess()
+{
+  if (!processPaused) return;
+
+#ifdef Q_OS_UNIX
+  if(::kill(process.pid(), SIGCONT))
+  {
+    // error
+    futureInterface.setPaused(true);
+  }
+  else
+  {
+    processPaused = false;
+  }
+#endif
+}
+
+void ctkCmdLineModuleProcessWatcher::cancelProcess()
+{
+  process.terminate();
+}
+
+int ctkCmdLineModuleProcessWatcher::updateProgress(float progress)
 {
   progressValue = static_cast(progress * 1000.0f);
   // normalize the value to lie between 0 and 1000.
@@ -74,16 +129,19 @@ int ctkCmdLineModuleProcessProgressWatcher::updateProgress(float progress)
   return progressValue;
 }
 
-int ctkCmdLineModuleProcessProgressWatcher::incrementProgress()
+int ctkCmdLineModuleProcessWatcher::incrementProgress()
 {
   if (++progressValue > 999) progressValue = 999;
   return progressValue;
 }
 
 ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args)
-  : process(NULL), location(location), args(args)
+  : location(location), args(args)
 {
   this->setCanCancel(true);
+#ifdef Q_OS_UNIX
+  this->setCanPause(true);
+#endif
 }
 
 ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask()
@@ -107,46 +165,32 @@ void ctkCmdLineModuleProcessTask::run()
     return;
   }
 
-  process = new QProcess();
-  process->setReadChannel(QProcess::StandardOutput);
+  QProcess process;
+  process.setReadChannel(QProcess::StandardOutput);
 
   QEventLoop localLoop;
-  QObject::connect(process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
-  QObject::connect(process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
+  QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit()));
+  QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit()));
 
-  QTimer pollCancelTimer;
-  pollCancelTimer.setInterval(500);
-  this->connect(&pollCancelTimer, SIGNAL(timeout()), SLOT(pollCancelState()));
+  process.start(location, args);
 
-  process->start(location, args);
-
-  ctkCmdLineModuleProcessProgressWatcher progressWatcher(*process, location, *this);
+  ctkCmdLineModuleProcessWatcher progressWatcher(process, location, *this);
   Q_UNUSED(progressWatcher)
 
   localLoop.exec();
 
-  if (process->error() != QProcess::UnknownError)
+  if (process.error() != QProcess::UnknownError)
   {
-    this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->errorString()));
+    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString()));
   }
-  else if (process->exitCode() != 0)
+  else if (process.exitCode() != 0)
   {
-    this->reportException(ctkCmdLineModuleRunException(location, process->exitCode(), process->readAllStandardError()));
+    this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.readAllStandardError()));
   }
 
-  this->setProgressValueAndText(1000, process->readAllStandardError());
+  this->setProgressValueAndText(1000, process.readAllStandardError());
 
   //this->reportResult(result);
   this->reportFinished();
 
-  delete process;
-
-}
-
-void ctkCmdLineModuleProcessTask::pollCancelState()
-{
-  if (this->isCanceled() && process->state() == QProcess::Running)
-  {
-    process->terminate();
-  }
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
index b1d9e0cb69..2d44a4303e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h
@@ -29,12 +29,13 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 class QProcess;
 
-class ctkCmdLineModuleProcessTask : public QObject, public ctkCmdLineModuleFutureInterface, public QRunnable
+class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable
 {
-  Q_OBJECT
 
 public:
 
@@ -45,26 +46,21 @@ class ctkCmdLineModuleProcessTask : public QObject, public ctkCmdLineModuleFutur
 
   void run();
 
-protected Q_SLOTS:
-
-  void pollCancelState();
-
 private:
 
-  QProcess* process;
   const QString location;
   const QStringList args;
 
 };
 
-class ctkCmdLineModuleProcessProgressWatcher : public QObject
+class ctkCmdLineModuleProcessWatcher : public QObject
 {
   Q_OBJECT
 
 public:
 
-  ctkCmdLineModuleProcessProgressWatcher(QProcess& process, const QString& location,
-                                         ctkCmdLineModuleFutureInterface& futureInterface);
+  ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location,
+                                 ctkCmdLineModuleFutureInterface& futureInterface);
 
 protected Q_SLOTS:
 
@@ -74,6 +70,10 @@ protected Q_SLOTS:
 
   void filterXmlError(const QString& error);
 
+  void pauseProcess();
+  void resumeProcess();
+  void cancelProcess();
+
 private:
 
   int updateProgress(float progress);
@@ -83,6 +83,9 @@ protected Q_SLOTS:
   QString location;
   ctkCmdLineModuleFutureInterface& futureInterface;
   ctkCmdLineModuleXmlProgressWatcher processXmlWatcher;
+  QFutureWatcher futureWatcher;
+  QTimer pollPauseTimer;
+  bool processPaused;
   int progressValue;
 };
 

From 69125fde7067469dab76bdbcb5bb355e862d9fb8 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Fri, 27 Jul 2012 09:37:01 +0200
Subject: [PATCH 080/247] Fix gcc 4.2.1 issue with super-class constructor.

---
 Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
index a3bde956de..93983d345c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h
@@ -41,7 +41,7 @@ class ctkCmdLineModuleFuture : public QFuture
   }
 
   explicit ctkCmdLineModuleFuture(ctkCmdLineModuleFutureInterface* p) // internal
-    : QFuture(p)
+    : QFuture(p)
   {
   }
 

From f9e14edf8d29d3b68b745fbbcdeff28412fd7a68 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 27 Jul 2012 09:37:48 -0400
Subject: [PATCH 081/247] Style: put schema version in implementation not
 header

Also clean up some dangling whitespace.
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 13 +++++++++----
 Libs/DICOM/Core/ctkDICOMDatabase.h   |  2 +-
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 47f3fc11ac..717ce2c882 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -432,6 +432,11 @@ QString ctkDICOMDatabase::schemaVersionLoaded()
   return QString("");
 }
 
+//------------------------------------------------------------------------------
+QString ctkDICOMDatabase::schemaVersion()
+{
+  return QString("0.5.1");
+};
 
 //------------------------------------------------------------------------------
 bool ctkDICOMDatabase::updateSchemaIfNeeded(const char* schemaFile)
@@ -449,16 +454,16 @@ bool ctkDICOMDatabase::updateSchema(const char* schemaFile)
   // backup filelist
   // reinit with the new schema
   // reinsert everything
- 
+
   Q_D(ctkDICOMDatabase);
   d->createBackupFileList();
- 
+
   d->resetLastInsertedValues();
   this->initializeDatabase(schemaFile);
 
   QStringList allFiles = d->filenames("Filenames_backup");
   emit schemaUpdateStarted(allFiles.length());
-  
+
   int progressValue = 0;
   foreach(QString file, allFiles)
   {
@@ -1024,7 +1029,7 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
   QString studyInstanceUID(ctkDataset.GetElementAsString(DCM_StudyInstanceUID) );
   QString seriesInstanceUID(ctkDataset.GetElementAsString(DCM_SeriesInstanceUID) );
   QString patientID(ctkDataset.GetElementAsString(DCM_PatientID) );
-  if ( patientID.isEmpty() && !studyInstanceUID.isEmpty() ) 	 
+  if ( patientID.isEmpty() && !studyInstanceUID.isEmpty() )
   { // Use study instance uid as patient id if patient id is empty - can happen on anonymized datasets
     // see: http://www.na-mic.org/Bug/view.php?id=2040
     logger.warn("Patient ID is empty, using studyInstanceUID as patient ID");
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h
index 19d210d377..566c51f991 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.h
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.h
@@ -119,7 +119,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   Q_INVOKABLE bool updateSchemaIfNeeded(const char* schemaFile = ":/dicom/dicom-schema.sql");
 
   /// returns the schema version needed by the current version of this code
-  Q_INVOKABLE QString schemaVersion() { return QString("0.5"); };
+  Q_INVOKABLE QString schemaVersion();
 
   /// returns the schema version for the currently open database
   /// in order to support schema updating

From b69a631e475a010d2c1cb095970f427e0c8eaf6e Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 27 Jul 2012 09:38:52 -0400
Subject: [PATCH 082/247] Update schema to include index on filenames

Addresses #218
---
 Libs/DICOM/Core/Resources/dicom-schema.sql | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index b93920dc61..368990d2cc 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -13,8 +13,10 @@ DROP TABLE IF EXISTS 'Series' ;
 DROP TABLE IF EXISTS 'Studies' ;
 DROP TABLE IF EXISTS 'Directories' ;
 
+DROP INDEX IF EXISTS 'ImagesFilenameIndex' ;
+
 CREATE TABLE 'SchemaInfo' ( 'Version' VARCHAR(1024) NOT NULL );
-INSERT INTO 'SchemaInfo' VALUES('0.5');
+INSERT INTO 'SchemaInfo' VALUES('0.5.1');
 
 CREATE TABLE 'Images' (
   'SOPInstanceUID' VARCHAR(64) NOT NULL,
@@ -61,6 +63,8 @@ CREATE TABLE 'Studies' (
   'StudyDescription' VARCHAR(255) NULL ,
   PRIMARY KEY ('StudyInstanceUID') );
 
+CREATE UNIQUE INDEX IF NOT EXISTS 'ImagesFilenameIndex' ON 'Images' ('Filename');
+
 CREATE TABLE 'Directories' (
   'Dirname' VARCHAR(1024) ,
   PRIMARY KEY ('Dirname') );

From 8e99afb72c0cc426ddbfe5ca1a8fef26f3536800 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 27 Jul 2012 09:43:15 -0400
Subject: [PATCH 083/247] Improve schema update documentation

---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 717ce2c882..2c5c746063 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -435,6 +435,13 @@ QString ctkDICOMDatabase::schemaVersionLoaded()
 //------------------------------------------------------------------------------
 QString ctkDICOMDatabase::schemaVersion()
 {
+  // When changing schema version:
+  // * make sure this matches the Version value in the
+  //   SchemaInfo table defined in Resources/dicom-schema.sql
+  // * make sure the 'Images' contains a 'Filename' column
+  //   so that the ctkDICOMDatabasePrivate::filenames method
+  //   still works.
+  //
   return QString("0.5.1");
 };
 

From 53edf43d0d7a659c1c6ce2ead73e984f1a0d8bbd Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 27 Jul 2012 11:11:40 -0400
Subject: [PATCH 084/247] Add a precache tags property

This is a hint to the database about what tags the application
is likely to request in the future so they can be cached.
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 32 ++++++++++++++++++++++++++++
 Libs/DICOM/Core/ctkDICOMDatabase.h   | 25 +++++++++++++++++++---
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 2c5c746063..0e5f276b1f 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -131,6 +131,8 @@ class ctkDICOMDatabasePrivate
   /// reading while the tag cache is writing
   QSqlDatabase TagCacheDatabase;
   QString TagCacheDatabaseFilename;
+  QStringList TagsToPrecache;
+  void precacheTags( const QString sopInstanceUID );
 
   int insertPatient(const ctkDICOMDataset& ctkDataset);
   void insertStudy(const ctkDICOMDataset& ctkDataset, int dbPatientID);
@@ -985,11 +987,38 @@ void ctkDICOMDatabasePrivate::insertSeries(const ctkDICOMDataset& ctkDataset, QS
     }
 }
 
+//------------------------------------------------------------------------------
+void ctkDICOMDatabase::setTagsToPrecache( const QStringList tags)
+{
+  Q_D(ctkDICOMDatabase);
+  d->TagsToPrecache = tags;
+}
+
+//------------------------------------------------------------------------------
+const QStringList ctkDICOMDatabase::tagsToPrecache()
+{
+  Q_D(ctkDICOMDatabase);
+  return d->TagsToPrecache;
+}
+
+//------------------------------------------------------------------------------
+void ctkDICOMDatabasePrivate::precacheTags( const QString sopInstanceUID )
+{
+  Q_Q(ctkDICOMDatabase);
+  foreach (const QString &tag, this->TagsToPrecache)
+    {
+    q->instanceValue(sopInstanceUID, tag);
+    }
+}
+
 //------------------------------------------------------------------------------
 void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const QString& filePath, bool storeFile, bool generateThumbnail)
 {
   Q_Q(ctkDICOMDatabase);
 
+  // this is the method that all other insert signatures end up calling
+  // after they have pre-parsed their arguments
+
   QMutexLocker lock(&insertMutex);
 
   // Check to see if the file has already been loaded
@@ -1150,6 +1179,9 @@ void ctkDICOMDatabasePrivate::insert( const ctkDICOMDataset& ctkDataset, const Q
               insertImageStatement.bindValue ( 2, seriesInstanceUID );
               insertImageStatement.bindValue ( 3, QDateTime::currentDateTime() );
               insertImageStatement.exec();
+
+              // insert was needed, so cache any application-requested tags
+              this->precacheTags(sopInstanceUID);
             }
         }
 
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.h b/Libs/DICOM/Core/ctkDICOMDatabase.h
index 566c51f991..2941c527b6 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.h
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.h
@@ -55,6 +55,7 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   Q_PROPERTY(bool isOpen READ isOpen)
   Q_PROPERTY(QString lastError READ lastError)
   Q_PROPERTY(QString databaseFilename READ databaseFilename)
+  Q_PROPERTY(QStringList tagsToPrecache READ tagsToPrecache WRITE setTagsToPrecache)
 
 public:
   explicit ctkDICOMDatabase(QObject *parent = 0);
@@ -146,6 +147,19 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   Q_INVOKABLE QStringList headerKeys ();
   Q_INVOKABLE QString headerValue (const QString key);
 
+  ///
+  /// \brief application-defined tags of interest
+  /// This list of tags is added to the internal tag cache during import
+  /// operations.  The list should be prepared by the application as
+  /// a hint to the database that these tags are likely to be accessed
+  /// later.  Internally, the database will cache the values of these
+  /// tags so that subsequent calls to fileValue or instanceValue will
+  /// be able to use the cache rather than re-reading the file.
+  /// @param tags should be a list of ascii hex group/element tags
+  ///  like "0008,0008" as in the instanceValue and fileValue calls
+  void setTagsToPrecache(const QStringList tags);
+  const QStringList tagsToPrecache();
+
   /// 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
@@ -161,9 +175,14 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMDatabase : public QObject
   ///                  does only make sense if a full object is received.
   /// @param @generateThumbnail If true, a thumbnail is generated.
   ///
-  Q_INVOKABLE void insert( const ctkDICOMDataset& ctkDataset, bool storeFile, bool generateThumbnail);
-  void insert ( DcmDataset *dataset, bool storeFile = true, bool generateThumbnail = true);
-  Q_INVOKABLE void insert ( const QString& filePath, bool storeFile = true, bool generateThumbnail = true, bool createHierarchy = true, const QString& destinationDirectoryName = QString() );
+  Q_INVOKABLE void insert( const ctkDICOMDataset& ctkDataset, 
+                              bool storeFile, bool generateThumbnail);
+  void insert ( DcmDataset *dataset, 
+                              bool storeFile = true, bool generateThumbnail = true);
+  Q_INVOKABLE void insert ( const QString& filePath, 
+                            bool storeFile = true, bool generateThumbnail = true, 
+                            bool createHierarchy = true, 
+                            const QString& destinationDirectoryName = QString() );
 
   /// Check if file is already in database and up-to-date
   bool fileExistsAndUpToDate(const QString& filePath);

From 481f5055ae54291373210873c2b8b2c8e30693ff Mon Sep 17 00:00:00 2001
From: Julien Finet 
Date: Fri, 27 Jul 2012 14:39:34 -0400
Subject: [PATCH 085/247] Add customization of ctkCmdLineModuleXslTransform

It is now possible to change the class name of each widget
For more advanced customization, the xsl can be overloaded
using setXslExtraTransformation.
---
 .../Resources/ctkCmdLineModuleXmlToQtUi.xsl   |  35 +-
 .../Core/Testing/Cpp/CMakeLists.txt           |  34 +-
 .../Cpp/ctkCmdLineModuleXslTransformTest.cpp  | 494 ++++++++++++++++++
 .../Core/ctkCmdLineModuleXmlValidator.cpp     |   4 +-
 .../Core/ctkCmdLineModuleXslTransform.cpp     | 137 +++--
 .../Core/ctkCmdLineModuleXslTransform.h       |  75 ++-
 6 files changed, 693 insertions(+), 86 deletions(-)
 create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp

diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
index 46af17b638..0c8d52668a 100644
--- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
+++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
@@ -166,13 +166,12 @@
     Match elements from the XML description
   ===================================================================
   -->
-
   
   
     
     
       
-      
+      
         
 
           
@@ -186,22 +185,24 @@
               
             
           
-
         
       
-
       
         
       
     
   
 
-
+  
   
   
     
     
-      
+      
         
         
         
@@ -213,7 +214,7 @@
       
     
   
-  
+
   
+
 
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt
index 8d484978ba..5624ae0dcb 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt
@@ -1,22 +1,40 @@
 set(KIT ${PROJECT_NAME})
+set(LIBRARY_NAME ${PROJECT_NAME})
 
 create_test_sourcelist(Tests ${KIT}CppTests.cpp
   ctkCmdLineModuleFutureTest.cpp
   ctkCmdLineModuleXmlProgressWatcherTest.cpp
+  ctkCmdLineModuleXslTransformTest.cpp
   )
 
 set(TestsToRun ${Tests})
 remove(TestsToRun ${KIT}CppTests.cpp)
 
-set(SRC_FILES ${Tests}
+set(Tests_SRCS ${Tests_SRCS}
   ctkCmdLineModuleSignalTester.cpp
 )
+set(Tests_MOC_SRCS ${Tests_MOC_SRCS}
+  ctkCmdLineModuleSignalTester.h
+)
 
-qt4_wrap_cpp(SRC_FILES ctkCmdLineModuleSignalTester.h)
-
-set(LIBRARY_NAME ${PROJECT_NAME})
+include_directories(
+  ${CMAKE_SOURCE_DIR}/Libs/Testing
+  ${CMAKE_CURRENT_BINARY_DIR}
+  )
 
-add_executable(${KIT}CppTests ${SRC_FILES})
+set(Tests_MOC_CPP)
+QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS})
+QT4_GENERATE_MOCS(
+  ctkCmdLineModuleXslTransformTest.cpp
+  )
+set(Tests_UI_CPP)
+if(TEST_UI_FORMS)
+  QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS})
+endif()
+set(Tests_RESOURCES_SRCS)
+QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES})
+
+add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS})
 target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES})
 add_dependencies(${KIT}CppTests ctkCmdLineTestModules)
 
@@ -24,7 +42,7 @@ add_dependencies(${KIT}CppTests ctkCmdLineTestModules)
 # Add Tests
 #
 
-foreach(_test ${TestsToRun})
-  SIMPLE_TEST(${_test})
-endforeach()
+SIMPLE_TEST(ctkCmdLineModuleFutureTest)
+SIMPLE_TEST(ctkCmdLineModuleXmlProgressWatcherTest)
+SIMPLE_TEST(ctkCmdLineModuleXslTransformTest)
 
diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp
new file mode 100644
index 0000000000..3b16cfef62
--- /dev/null
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp
@@ -0,0 +1,494 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  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.
+
+=========================================================================*/
+
+// Qt includes
+#include 
+#include 
+#include 
+#include 
+
+// CTK includes
+#include "ctkCmdLineModuleXslTransform.h"
+#include "ctkTest.h"
+
+// ----------------------------------------------------------------------------
+class ctkCmdLineModuleXslTransformTester: public QObject
+{
+  Q_OBJECT
+private slots:
+  void testTransform();
+  void testTransform_data();
+
+  void testBindVariable();
+  void testBindVariable_data();
+
+  void testXslExtraTransformation();
+  void testXslExtraTransformation_data();
+};
+
+QString invalidXml =
+  ""
+  "";
+
+QString header =
+  ""
+  ""
+  " "
+  " A Test"
+  " "
+  " 0.1.0"
+  " "
+  " "
+  " "
+  " ";
+
+QString footer =
+  "\n";
+
+QString mainWidgetHeader =
+  "\n"
+  "    ATest\n"
+  "    \n"
+  "        \n";
+
+QString mainWidgetFooter =
+  "            \n"
+  "                \n"
+  "                    \n"
+  "                        Qt::Vertical\n"
+  "                    \n"
+  "                \n"
+  "            \n"
+  "        \n"
+  "    \n"
+  "    \n"
+  "\n";
+
+QString parametersHeader =
+  " "
+  "  "
+  "  ";
+
+QString parametersFooter =
+  " \n";
+
+QString parametersWidgetHeader =
+  "            \n"
+  "                \n"
+  "                    \n"
+  "                        Parameters\n"
+  "                    \n"
+  "                    \n"
+  "                        Parameters\n"
+  "                    \n"
+  "                    \n"
+  "                        true\n"
+  "                    \n"
+  ;
+
+QString parametersWidgetEmptyLayout =
+  "                    \n";
+
+QString parametersLayoutHeader =
+  "                    \n";
+
+QString parametersLayoutFooter =
+  "                    \n";
+
+QString parametersWidgetFooter =
+  "                \n"
+  "            \n"
+  ;
+QString integer =
+  ""
+  " integer"
+  " -i"
+  " --integer"
+  " "
+  " "
+  " 1"
+  ""
+  ;
+
+QString integerWidgetLabel =
+  "                        \n"
+  "                            \n"
+  "                                \n"
+  "                                    \n"
+  "                                        0\n"
+  "                                        0\n"
+  "                                    \n"
+  "                                \n"
+  "                                \n"
+  "                                    Integer\n"
+  "                                \n"
+  "                            \n"
+  "                        \n"
+  ;
+QString integerWidgetSpinBoxHeader =
+  "                        \n"
+  ;
+QString integerWidgetSpinBox =
+  "                            \n"
+  "                                \n"
+  "                                    -999999999\n"
+  "                                \n"
+  "                                \n"
+  "                                    999999999\n"
+  "                                \n"
+  "                                \n"
+  "                                    Integer description\n"
+  "                                \n"
+  "                                \n"
+  "                                    int\n"
+  "                                \n"
+  "                                \n"
+  "                                    value\n"
+  "                                \n"
+  "                                \n"
+  "                                    1\n"
+  "                                \n"
+  "                                \n"
+  "                                    -i\n"
+  "                                \n"
+  "                                \n"
+  "                                    --integer\n"
+  "                                \n"
+  "                                \n"
+  "                                    Integer description\n"
+  "                                \n"
+  "                                \n"
+  "                                    Integer\n"
+  "                                \n"
+  "                                \n"
+  "                                    1\n"
+  "                                \n"
+  "                            \n"
+  ;
+QString integerWidgetSpinBoxFooter =
+  "                        \n"
+  ;
+
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testTransform()
+{
+  ctkCmdLineModuleXslTransform transformer;
+
+  QFETCH(QString, input);
+  QByteArray inputByteArray = input.toUtf8();
+  QBuffer inputBuffer(&inputByteArray);
+  transformer.setInput(&inputBuffer);
+
+  QBuffer output;
+  output.open(QBuffer::ReadWrite);
+  transformer.setOutput(&output);
+
+  QFETCH(bool, expectedSuccess);
+  bool success = transformer.transform();
+  if (!success)
+    {
+    qDebug() << transformer.errorString();
+    QCOMPARE(transformer.error(), true);
+    QVERIFY(!transformer.errorString().isEmpty());
+    }
+  QCOMPARE(success, expectedSuccess);
+
+  QFETCH(QString, expectedOutput);
+  QCOMPARE(QString(output.readAll()), expectedOutput);
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testTransform_data()
+{
+  QTest::addColumn("input");
+  QTest::addColumn("expectedSuccess");
+  QTest::addColumn("expectedOutput");
+
+  QTest::newRow("null") << QString() << false << QString();
+  QTest::newRow("empty") << QString("") << false << QString();
+  QTest::newRow("invalidXml") << invalidXml << false << QString();
+  QString noParameter = header + footer;
+  QString noParameterUi = mainWidgetHeader + mainWidgetFooter;
+  QTest::newRow("no parameter") << noParameter << true << noParameterUi;
+
+  QString justParameters =
+    header
+    + parametersHeader
+    + parametersFooter
+    + footer;
+  QString justParametersUi =
+    mainWidgetHeader
+    + parametersWidgetHeader
+    + parametersWidgetEmptyLayout
+    + parametersWidgetFooter
+    + mainWidgetFooter;
+  QTest::newRow("just parameters") << justParameters << true << justParametersUi;
+
+  QString integerParameter =
+    header
+    + parametersHeader
+    + integer
+    + parametersFooter
+    + footer;
+  QString integerParameterUi =
+    mainWidgetHeader
+    + parametersWidgetHeader
+    + parametersLayoutHeader
+    + integerWidgetLabel
+    + integerWidgetSpinBoxHeader
+    + integerWidgetSpinBox
+    + integerWidgetSpinBoxFooter
+    + parametersLayoutFooter
+    + parametersWidgetFooter
+    + mainWidgetFooter;
+  QTest::newRow("integer") << integerParameter << true << integerParameterUi;
+
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testBindVariable()
+{
+  ctkCmdLineModuleXslTransform transformer;
+
+  QFETCH(QString, input);
+  QByteArray inputArray(input.toUtf8());
+  QBuffer inputBuffer(&inputArray);
+  transformer.setInput(&inputBuffer);
+
+  QBuffer output;
+  output.open(QBuffer::ReadWrite);
+  transformer.setOutput(&output);
+
+  QFETCH(QString, variableName);
+  QFETCH(QString, variableValue);
+  transformer.bindVariable(variableName, variableValue);
+
+  transformer.transform();
+
+  QFETCH(QString, expectedOutput);
+  QCOMPARE(QString(transformer.output()->readAll()), expectedOutput);
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testBindVariable_data()
+{
+  QTest::addColumn("input");
+  QTest::addColumn("variableName");
+  QTest::addColumn("variableValue");
+  QTest::addColumn("expectedOutput");
+
+  QString integerParameter =
+    header
+    + parametersHeader
+    + integer
+    + parametersFooter
+    + footer;
+  QString integerParameterUi =
+    mainWidgetHeader
+    + parametersWidgetHeader
+    + parametersLayoutHeader
+    + integerWidgetLabel
+    + integerWidgetSpinBoxHeader
+    + integerWidgetSpinBox
+    + integerWidgetSpinBoxFooter
+    + parametersLayoutFooter
+    + parametersWidgetFooter
+    + mainWidgetFooter;
+  integerParameterUi.replace("QSpinBox", "ctkSliderWidget");
+  QTest::newRow("QSpinBox -> ctkSpinBox") << integerParameter
+                                          << QString("integerWidget")
+                                          << QString("ctkSliderWidget")
+                                          << integerParameterUi;
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation()
+{
+  ctkCmdLineModuleXslTransform transformer;
+
+  QFETCH(QString, input);
+  QByteArray inputArray(input.toUtf8());
+  QBuffer inputBuffer(&inputArray);
+  transformer.setInput(&inputBuffer);
+
+  QBuffer output;
+  output.open(QBuffer::ReadWrite);
+  transformer.setOutput(&output);
+
+  QFETCH(QString, extra);
+  QByteArray extraTransformationArray(extra.toUtf8());
+  QBuffer extraTransformationBuffer(&extraTransformationArray);
+  transformer.setXslExtraTransformation(&extraTransformationBuffer);
+
+  transformer.transform();
+
+  QFETCH(QString, expectedOutput);
+  //qDebug() << transformer.output();
+  //qDebug() << expectedOutput;
+  QCOMPARE(QString(transformer.output()->readAll()), expectedOutput);
+}
+
+// ----------------------------------------------------------------------------
+void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation_data()
+{
+  QString extra =
+    "\n"
+    "\n"
+    "\n"
+    "  \n"
+    "    \n"
+    "      \n"
+    "        \n"
+    "          \n"
+    "            -999999999\n"
+    "          \n"
+    "          \n"
+    "            999999999\n"
+    "          \n"
+    "        \n"
+    "        \n"
+    "      \n"
+    "    "
+    "    \n"
+    "      \n"
+    "        \n"
+    "          \n"
+    "            -999999999\n"
+    "          \n"
+    "          \n"
+    "            999999999\n"
+    "          \n"
+    "        \n"
+    "        \n"
+    "      \n"
+    "    \n"
+    "  \n"
+    "\n"
+    "\n"
+    ;
+  QString integerWidgetSliderSpinBox =
+    "                            \n"
+    "                                \n"
+    "                                    \n"
+    "                                        \n"
+    "                                            -999999999\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            999999999\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer description\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            int\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            value\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            1\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            -i\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            --integer\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer description\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            1\n"
+    "                                        \n"
+    "                                    \n"
+    "                                \n"
+    "                                \n"
+    "                                    \n"
+    "                                        \n"
+    "                                            -999999999\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            999999999\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer description\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            int\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            value\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            1\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            -i\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            --integer\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer description\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            Integer\n"
+    "                                        \n"
+    "                                        \n"
+    "                                            1\n"
+    "                                        \n"
+    "                                    \n"
+    "                                \n"
+    "                            \n"
+    ;
+  QTest::addColumn("input");
+  QTest::addColumn("extra");
+  QTest::addColumn("expectedOutput");
+
+  QString integerParameter =
+    header
+    + parametersHeader
+    + integer
+    + parametersFooter
+    + footer;
+  QString integerParameterUi =
+    mainWidgetHeader
+    + parametersWidgetHeader
+    + parametersLayoutHeader
+    + integerWidgetLabel
+    + integerWidgetSpinBoxHeader
+    + integerWidgetSliderSpinBox
+    + integerWidgetSpinBoxFooter
+    + parametersLayoutFooter
+    + parametersWidgetFooter
+    + mainWidgetFooter;
+  QTest::newRow("QSpinBox -> QSlider+QSpinBox") << integerParameter
+                                          << extra
+                                          << integerParameterUi;
+
+}
+
+// ----------------------------------------------------------------------------
+CTK_TEST_MAIN(ctkCmdLineModuleXslTransformTest)
+#include "moc_ctkCmdLineModuleXslTransformTest.cpp"
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
index cee8736dfa..9b6674f9b6 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
@@ -95,10 +95,10 @@ bool ctkCmdLineModuleXmlValidator::validateInput()
 
 bool ctkCmdLineModuleXmlValidator::error() const
 {
-  return !ErrorStr.isEmpty();
+  return !this->ErrorStr.isEmpty();
 }
 
 QString ctkCmdLineModuleXmlValidator::errorString() const
 {
-  return ErrorStr;
+  return this->ErrorStr;
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
index afff3d67d7..891a9e899c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
@@ -1,70 +1,93 @@
 /*=============================================================================
-  
+
   Library: CTK
-  
+
   Copyright (c) German Cancer Research Center,
     Division of Medical and Biological Informatics
-    
+
   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
-    
+
   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.
-  
-=============================================================================*/
-
-#include "ctkCmdLineModuleXslTransform.h"
 
-#include "ctkCmdLineModuleXmlMsgHandler_p.h"
+=============================================================================*/
 
-#include 
+// Qt includes
 #include 
+#include 
+#include 
 #include 
 #include 
-#include 
-
-#include 
 
+// CTK includes
+#include "ctkCmdLineModuleXslTransform.h"
+#include "ctkCmdLineModuleXmlMsgHandler_p.h"
 
 ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIODevice *output)
-  : ctkCmdLineModuleXmlValidator(input),
-    Validate(false), OutputSchema(0), Transformation(0), Output(output)
+  : ctkCmdLineModuleXmlValidator(input)
+  , Validate(false)
+  , OutputSchema(0)
+  , Transformation(0)
+  , Output(output)
+  , XslTransform(QXmlQuery::XSLT20)
+  , MsgHandler(0)
+{
+  this->MsgHandler = new ctkCmdLineModuleXmlMsgHandler();
+  this->XslTransform.setMessageHandler(this->MsgHandler);
+
+  this->bindVariable("executableWidget", QVariant(QString("QWidget")));
+  this->bindVariable("parametersWidget", QVariant(QString("ctkCollapsibleGroupBox")));
+  this->bindVariable("booleanWidget", QVariant(QString("QCheckBox")));
+  this->bindVariable("integerWidget", QVariant(QString("QSpinBox")));
+  this->bindVariable("floatingWidget", QVariant(QString("QDoubleSpinBox")));
+  this->bindVariable("vectorWidget", QVariant(QString("QLineEdit")));
+  this->bindVariable("enumWidget", QVariant(QString("QComboBox")));
+  this->bindVariable("imageWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("directoryWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("pointWidget", QVariant(QString("ctkCoordinatesWidget")));
+  this->bindVariable("unsupportedWidget", QVariant(QString("QLabel")));
+}
+
+ctkCmdLineModuleXslTransform::~ctkCmdLineModuleXslTransform()
 {
+  delete this->MsgHandler;
 }
 
 void ctkCmdLineModuleXslTransform::setOutput(QIODevice* output)
 {
-  Output = output;
+  this->Output = output;
 }
 
 QIODevice* ctkCmdLineModuleXslTransform::output() const
 {
-  return Output;
+  return this->Output;
 }
 
 void ctkCmdLineModuleXslTransform::setOutputSchema(QIODevice *output)
 {
-  OutputSchema = output;
+  this->OutputSchema = output;
 }
 
 bool ctkCmdLineModuleXslTransform::transform()
 {
+  this->ErrorStr.clear();
+
   if (!Output)
   {
-    ErrorStr = "No output device set";
+    this->ErrorStr = "No output device set";
     return false;
   }
-
-  QIODevice* inputDevice = input();
+  QIODevice* inputDevice = this->input();
   if (!inputDevice)
   {
-    ErrorStr = "No input set for deriving an output.";
+    this->ErrorStr = "No input set for deriving an output.";
     return false;
   }
   else if (!(inputDevice->openMode() & QIODevice::ReadOnly))
@@ -73,72 +96,94 @@ bool ctkCmdLineModuleXslTransform::transform()
   }
   inputDevice->reset();
 
-  ctkCmdLineModuleXmlMsgHandler msgHandler;
 
-  QXmlQuery xslTransform(QXmlQuery::XSLT20);
-  xslTransform.setMessageHandler(&msgHandler);
-  if (!xslTransform.setFocus(inputDevice))
+  if (!this->XslTransform.setFocus(inputDevice))
   {
     QString msg("Error transforming XML input: %1");
-    ErrorStr = msg.arg(msgHandler.statusMessage());
+    this->ErrorStr = msg.arg(this->MsgHandler->statusMessage());
     return false;
   }
 
-  QIODevice* transformation = Transformation;
+  QIODevice* transformation = this->Transformation;
   QScopedPointer defaultTransform(new QFile(":/ctkCmdLineModuleXmlToQtUi.xsl"));
   if (!transformation)
   {
     transformation = defaultTransform.data();
     transformation->open(QIODevice::ReadOnly);
   }
-  xslTransform.setQuery(transformation);
+  QString query(transformation->readAll());
+  QString extra;
+  foreach(QIODevice* extraIODevice, this->ExtraTransformations)
+    {
+    extraIODevice->open(QIODevice::ReadOnly);
+    extra += extraIODevice->readAll();
+    }
+  query.replace("", extra);
+#if 0
+  qDebug() << query;
+#endif
+  this->XslTransform.setQuery(query);
 
   bool closeOutput = false;
-  if (!(Output->openMode() & QIODevice::WriteOnly))
+  if (!(this->Output->openMode() & QIODevice::WriteOnly))
   {
-    Output->open(QIODevice::WriteOnly);
+    this->Output->open(QIODevice::WriteOnly);
     closeOutput = true;
   }
 
-  if (!xslTransform.evaluateTo(Output))
+  if (!this->XslTransform.evaluateTo(this->Output))
   {
     QString msg("Error transforming XML input, at line %1, column %2: %3");
-    ErrorStr = msg.arg(msgHandler.line()).arg(msgHandler.column())
-        .arg(msgHandler.statusMessage());
+    this->ErrorStr = msg.arg(this->MsgHandler->line()).arg(this->MsgHandler->column())
+      .arg(this->MsgHandler->statusMessage());
     return false;
   }
 
+#if 0
+  qDebug() << this->Output;
+#endif
+
   if (closeOutput)
   {
-    Output->close();
+    this->Output->close();
   }
   else
   {
-    Output->reset();
+    this->Output->reset();
   }
 
-  if (Validate)
+  if (this->Validate)
   {
-    return validateOutput();
+    return this->validateOutput();
   }
   return true;
 }
 
 void ctkCmdLineModuleXslTransform::setXslTransformation(QIODevice *transformation)
 {
-  Transformation = transformation;
+  this->Transformation = transformation;
+}
+
+void ctkCmdLineModuleXslTransform::bindVariable(const QString& name, const QVariant& value)
+{
+  this->XslTransform.bindVariable(name, value);
+}
+
+void ctkCmdLineModuleXslTransform::setXslExtraTransformations(QList transformations)
+{
+  this->ExtraTransformations = transformations;
 }
 
 void ctkCmdLineModuleXslTransform::setValidateOutput(bool validate)
 {
-  Validate = validate;
+  this->Validate = validate;
 }
 
 bool ctkCmdLineModuleXslTransform::validateOutput()
 {
-  ErrorStr.clear();
+  this->ErrorStr.clear();
 
-  QIODevice* outputSchema = OutputSchema;
+  QIODevice* outputSchema = this->OutputSchema;
 
   // If there is no custom schema for validating the output, we just return.
   // The QtDesigner.xsd schema below (which should be the default) exhausts
@@ -181,15 +226,15 @@ bool ctkCmdLineModuleXslTransform::validateOutput()
 
 bool ctkCmdLineModuleXslTransform::error() const
 {
-  return ctkCmdLineModuleXmlValidator::error() || !ErrorStr.isEmpty();
+  return ctkCmdLineModuleXmlValidator::error() || !this->ErrorStr.isEmpty();
 }
 
 QString ctkCmdLineModuleXslTransform::errorString() const
 {
-  QString errStr = ctkCmdLineModuleXmlValidator::errorString();
+  QString errStr = this->ctkCmdLineModuleXmlValidator::errorString();
   if (errStr.isEmpty())
   {
-    return ErrorStr;
+    return this->ErrorStr;
   }
   return errStr;
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
index c99d6915f1..cf735f8c0b 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
@@ -1,44 +1,49 @@
 /*=============================================================================
-  
+
   Library: CTK
-  
+
   Copyright (c) German Cancer Research Center,
     Division of Medical and Biological Informatics
-    
+
   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
-    
+
   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 CTKCMDLINEMODULEXSLTRANSFORM_H
-#define CTKCMDLINEMODULEXSLTRANSFORM_H
+#ifndef __ctkCmdLineModuleXslTransform_h
+#define __ctkCmdLineModuleXslTransform_h
 
+// CTK includes
 #include "ctkCommandLineModulesCoreExport.h"
 #include "ctkCmdLineModuleXmlValidator.h"
+class ctkCmdLineModuleXmlMsgHandler;
 
+// Qt includes
+#include 
 #include 
-
+#include 
 class QIODevice;
 
 /**
  * \ingroup CommandLineModulesCore
  */
 class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
-    : public ctkCmdLineModuleXmlValidator
+  : public ctkCmdLineModuleXmlValidator
 {
 
 public:
 
   ctkCmdLineModuleXslTransform(QIODevice* input = 0, QIODevice* output = 0);
+  virtual ~ctkCmdLineModuleXslTransform();
 
   void setOutput(QIODevice* output);
   QIODevice* output() const;
@@ -49,7 +54,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
    * @brief Transforms an XML input via a XSL transformation.
    *
    * This method assumes that the input set via setInput() or supplied
-   * in the constructor is a valid XML fragment.
+   * in the constructor is a valid, non empty XML fragment.
    *
    * @return
    */
@@ -57,10 +62,41 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
 
   void setXslTransformation(QIODevice* transformation);
 
+  /**
+   * @brief XSL to be injected in the main XSL.
+   *
+   * This can be used to potentially overwrite templates.
+   * To avoid ambiguity, specify a priority > 1 in your overwriting templates
+   *
+   * @return
+   */
+  inline void setXslExtraTransformation(QIODevice* transformation);
+  void setXslExtraTransformations(QList transformations);
+
+  /**
+   *  @brief Binds the variable name to the value so that $name can be used
+   *  from within the query to refer to the value.
+   *  In the default XslTransformation, the widget classes are variable and can
+   *  be replaced with a new binding.
+   *  @sa QXmlQuery::bindVariable()
+   */
+  void bindVariable(const QString& name, const QVariant& value);
+
   void setValidateOutput(bool validate);
 
-  bool error() const;
-  QString errorString() const;
+  /** @brief returns true if an error occured
+   *  transform() sets the error flag if an error occured when transforming the
+   *  XML file into XSL.
+   *  \sa errorString
+   */
+  virtual bool error() const;
+
+  /** @brief Error message if any
+   *  transform() sets the error message if an error occured when transforming
+   * the XML file into XSL.
+   *  \sa error
+   */
+  virtual QString errorString() const;
 
 private:
 
@@ -70,9 +106,20 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
 
   QIODevice* OutputSchema;
   QIODevice* Transformation;
-
   QIODevice* Output;
+
+  QXmlQuery XslTransform;
+  QList ExtraTransformations;
+  ctkCmdLineModuleXmlMsgHandler* MsgHandler;
+
   QString ErrorStr;
 };
 
+void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transformation)
+{
+  QList transformations;
+  transformations<setXslExtraTransformations(transformations);
+}
+
 #endif // CTKCMDLINEMODULEXSLTRANSFORM_H

From 7e1ec6e31768410817283ec82d1576319b932b33 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 30 Jul 2012 11:50:03 +0200
Subject: [PATCH 086/247] Added option to format xml output from xsl
 transformations.

---
 .../Cpp/ctkCmdLineModuleXslTransformTest.cpp  | 60 ++-----------------
 .../Core/ctkCmdLineModuleXslTransform.cpp     | 33 +++++++++-
 .../Core/ctkCmdLineModuleXslTransform.h       | 27 ++++++---
 3 files changed, 56 insertions(+), 64 deletions(-)

diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp
index 3b16cfef62..6907d85f5d 100644
--- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp
+++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp
@@ -156,30 +156,12 @@ QString integerWidgetSpinBox =
   "                                \n"
   "                                    Integer description\n"
   "                                \n"
-  "                                \n"
-  "                                    int\n"
-  "                                \n"
   "                                \n"
   "                                    value\n"
   "                                \n"
   "                                \n"
   "                                    1\n"
   "                                \n"
-  "                                \n"
-  "                                    -i\n"
-  "                                \n"
-  "                                \n"
-  "                                    --integer\n"
-  "                                \n"
-  "                                \n"
-  "                                    Integer description\n"
-  "                                \n"
-  "                                \n"
-  "                                    Integer\n"
-  "                                \n"
-  "                                \n"
-  "                                    1\n"
-  "                                \n"
   "                            \n"
   ;
 QString integerWidgetSpinBoxFooter =
@@ -201,6 +183,8 @@ void ctkCmdLineModuleXslTransformTester::testTransform()
   output.open(QBuffer::ReadWrite);
   transformer.setOutput(&output);
 
+  transformer.setFormatXmlOutput(true);
+
   QFETCH(bool, expectedSuccess);
   bool success = transformer.transform();
   if (!success)
@@ -277,6 +261,8 @@ void ctkCmdLineModuleXslTransformTester::testBindVariable()
   output.open(QBuffer::ReadWrite);
   transformer.setOutput(&output);
 
+  transformer.setFormatXmlOutput(true);
+
   QFETCH(QString, variableName);
   QFETCH(QString, variableValue);
   transformer.bindVariable(variableName, variableValue);
@@ -333,6 +319,8 @@ void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation()
   output.open(QBuffer::ReadWrite);
   transformer.setOutput(&output);
 
+  transformer.setFormatXmlOutput(true);
+
   QFETCH(QString, extra);
   QByteArray extraTransformationArray(extra.toUtf8());
   QBuffer extraTransformationBuffer(&extraTransformationArray);
@@ -397,30 +385,12 @@ void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation_data()
     "                                        \n"
     "                                            Integer description\n"
     "                                        \n"
-    "                                        \n"
-    "                                            int\n"
-    "                                        \n"
     "                                        \n"
     "                                            value\n"
     "                                        \n"
     "                                        \n"
     "                                            1\n"
     "                                        \n"
-    "                                        \n"
-    "                                            -i\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            --integer\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            Integer description\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            Integer\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            1\n"
-    "                                        \n"
     "                                    \n"
     "                                \n"
     "                                \n"
@@ -434,30 +404,12 @@ void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation_data()
     "                                        \n"
     "                                            Integer description\n"
     "                                        \n"
-    "                                        \n"
-    "                                            int\n"
-    "                                        \n"
     "                                        \n"
     "                                            value\n"
     "                                        \n"
     "                                        \n"
     "                                            1\n"
     "                                        \n"
-    "                                        \n"
-    "                                            -i\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            --integer\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            Integer description\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            Integer\n"
-    "                                        \n"
-    "                                        \n"
-    "                                            1\n"
-    "                                        \n"
     "                                    \n"
     "                                \n"
     "                            \n"
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
index 891a9e899c..99a807aecd 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 
 // CTK includes
 #include "ctkCmdLineModuleXslTransform.h"
@@ -33,6 +34,7 @@
 ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIODevice *output)
   : ctkCmdLineModuleXmlValidator(input)
   , Validate(false)
+  , Format(false)
   , OutputSchema(0)
   , Transformation(0)
   , Output(output)
@@ -75,6 +77,16 @@ void ctkCmdLineModuleXslTransform::setOutputSchema(QIODevice *output)
   this->OutputSchema = output;
 }
 
+bool ctkCmdLineModuleXslTransform::formatXmlOutput() const
+{
+  return this->Format;
+}
+
+void ctkCmdLineModuleXslTransform::setFormatXmlOutput(bool format)
+{
+  this->Format = format;
+}
+
 bool ctkCmdLineModuleXslTransform::transform()
 {
   this->ErrorStr.clear();
@@ -131,7 +143,17 @@ bool ctkCmdLineModuleXslTransform::transform()
     closeOutput = true;
   }
 
-  if (!this->XslTransform.evaluateTo(this->Output))
+  QScopedPointer xmlSerializer;
+  if (Format)
+  {
+    xmlSerializer.reset(new QXmlFormatter(this->XslTransform, this->Output));
+  }
+  else
+  {
+    xmlSerializer.reset(new QXmlSerializer(this->XslTransform, this->Output));
+  }
+
+  if (!this->XslTransform.evaluateTo(xmlSerializer.data()))
   {
     QString msg("Error transforming XML input, at line %1, column %2: %3");
     this->ErrorStr = msg.arg(this->MsgHandler->line()).arg(this->MsgHandler->column())
@@ -169,7 +191,14 @@ void ctkCmdLineModuleXslTransform::bindVariable(const QString& name, const QVari
   this->XslTransform.bindVariable(name, value);
 }
 
-void ctkCmdLineModuleXslTransform::setXslExtraTransformations(QList transformations)
+void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transformation)
+{
+  QList transformations;
+  transformations<setXslExtraTransformations(transformations);
+}
+
+void ctkCmdLineModuleXslTransform::setXslExtraTransformations(const QList& transformations)
 {
   this->ExtraTransformations = transformations;
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
index cf735f8c0b..5bca881435 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
@@ -50,6 +50,22 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
 
   void setOutputSchema(QIODevice* output);
 
+  /**
+   * @brief Returns \code true if the XSL output will be formatted.
+   * @return \code true if the ouptut will be formatted, \code false otherwise.
+   */
+  bool formatXmlOutput() const;
+
+  /**
+   * @brief Formats the XSL output to be human-readable.
+   *
+   * It is assumed that the XSL output is valid XML. The output will be
+   * formatted with an indentation depth of four spaces. Note that setting
+   * \e format to \code true increases compuational overhead and memory
+   * requirements and is usually only done for testing or debugging purposes.
+   */
+  void setFormatXmlOutput(bool format);
+
   /**
    * @brief Transforms an XML input via a XSL transformation.
    *
@@ -70,8 +86,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
    *
    * @return
    */
-  inline void setXslExtraTransformation(QIODevice* transformation);
-  void setXslExtraTransformations(QList transformations);
+  void setXslExtraTransformation(QIODevice* transformation);
+  void setXslExtraTransformations(const QList& transformations);
 
   /**
    *  @brief Binds the variable name to the value so that $name can be used
@@ -103,6 +119,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
   bool validateOutput();
 
   bool Validate;
+  bool Format;
 
   QIODevice* OutputSchema;
   QIODevice* Transformation;
@@ -115,11 +132,5 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
   QString ErrorStr;
 };
 
-void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transformation)
-{
-  QList transformations;
-  transformations<setXslExtraTransformations(transformations);
-}
 
 #endif // CTKCMDLINEMODULEXSLTRANSFORM_H

From dae2f987fff0dab6e310a8de0159de338939b376 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 30 Jul 2012 12:05:10 +0200
Subject: [PATCH 087/247] Use pimpl idiom for public xml/xsl classes.

---
 .../Core/ctkCmdLineModuleXmlValidator.cpp     |  45 ++--
 .../Core/ctkCmdLineModuleXmlValidator.h       |   9 +-
 .../Core/ctkCmdLineModuleXslTransform.cpp     | 200 ++++++++++--------
 .../Core/ctkCmdLineModuleXslTransform.h       |  19 +-
 4 files changed, 150 insertions(+), 123 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
index 9b6674f9b6..9f2f9103dc 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp
@@ -30,37 +30,56 @@
 
 #include 
 
+class ctkCmdLineModuleXmlValidatorPrivate
+{
+public:
+
+  ctkCmdLineModuleXmlValidatorPrivate()
+    : Input(NULL), InputSchema(NULL)
+  {}
+
+  QIODevice* Input;
+  QIODevice* InputSchema;
+
+  QString ErrorStr;
+};
+
 ctkCmdLineModuleXmlValidator::ctkCmdLineModuleXmlValidator(QIODevice *input)
-  : Input(input), InputSchema(0)
+  : d(new ctkCmdLineModuleXmlValidatorPrivate)
+{
+  d->Input = input;
+}
+
+ctkCmdLineModuleXmlValidator::~ctkCmdLineModuleXmlValidator()
 {
 }
 
 void ctkCmdLineModuleXmlValidator::setInput(QIODevice *input)
 {
-  Input = input;
+  d->Input = input;
 }
 
 QIODevice* ctkCmdLineModuleXmlValidator::input() const
 {
-  return Input;
+  return d->Input;
 }
 
 void ctkCmdLineModuleXmlValidator::setInputSchema(QIODevice *input)
 {
-  InputSchema = input;
+  d->InputSchema = input;
 }
 
 bool ctkCmdLineModuleXmlValidator::validateInput()
 {
-  ErrorStr.clear();
+  d->ErrorStr.clear();
 
-  if (!Input)
+  if (!d->Input)
   {
-    ErrorStr = "No input set for validation.";
+    d->ErrorStr = "No input set for validation.";
     return false;
   }
 
-  QIODevice* inputSchema = InputSchema;
+  QIODevice* inputSchema = d->InputSchema;
   QScopedPointer defaultInputSchema(new QFile(":/ctkCmdLineModule.xsd"));
   if (!inputSchema)
   {
@@ -76,16 +95,16 @@ bool ctkCmdLineModuleXmlValidator::validateInput()
   if (!schema.load(inputSchema))
   {
     QString msg("Invalid input schema at line %1, column %2: %3");
-    ErrorStr = msg.arg(errorHandler.line()).arg(errorHandler.column()).arg(errorHandler.statusMessage());
+    d->ErrorStr = msg.arg(errorHandler.line()).arg(errorHandler.column()).arg(errorHandler.statusMessage());
     return false;
   }
 
   QXmlSchemaValidator validator(schema);
 
-  if (!validator.validate(Input))
+  if (!validator.validate(d->Input))
   {
     QString msg("Error validating CLI XML description, at line %1, column %2: %3");
-    ErrorStr = msg.arg(errorHandler.line()).arg(errorHandler.column())
+    d->ErrorStr = msg.arg(errorHandler.line()).arg(errorHandler.column())
                 .arg(errorHandler.statusMessage());
     return false;
   }
@@ -95,10 +114,10 @@ bool ctkCmdLineModuleXmlValidator::validateInput()
 
 bool ctkCmdLineModuleXmlValidator::error() const
 {
-  return !this->ErrorStr.isEmpty();
+  return !d->ErrorStr.isEmpty();
 }
 
 QString ctkCmdLineModuleXmlValidator::errorString() const
 {
-  return this->ErrorStr;
+  return d->ErrorStr;
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h
index 1a426a93df..67a629c11c 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h
@@ -24,7 +24,9 @@
 
 #include 
 
-#include 
+#include 
+
+class ctkCmdLineModuleXmlValidatorPrivate;
 
 class QIODevice;
 
@@ -37,6 +39,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlValidator
 public:
 
   ctkCmdLineModuleXmlValidator(QIODevice* input = 0);
+  ~ctkCmdLineModuleXmlValidator();
 
   void setInput(QIODevice* input);
   QIODevice* input() const;
@@ -50,10 +53,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlValidator
 
 private:
 
-  QIODevice* Input;
-  QIODevice* InputSchema;
+  QScopedPointer d;
 
-  QString ErrorStr;
 };
 
 #endif // CTKCMDLINEMODULEXMLVALIDATOR_H
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
index 99a807aecd..47590fbc74 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -31,19 +32,86 @@
 #include "ctkCmdLineModuleXslTransform.h"
 #include "ctkCmdLineModuleXmlMsgHandler_p.h"
 
+class ctkCmdLineModuleXslTransformPrivate
+{
+public:
+
+  ctkCmdLineModuleXslTransformPrivate(QIODevice *output)
+    : Validate(false)
+    , Format(false)
+    , OutputSchema(0)
+    , Transformation(0)
+    , Output(output)
+    , XslTransform(QXmlQuery::XSLT20)
+  {
+    this->XslTransform.setMessageHandler(&this->MsgHandler);
+  }
+
+  bool validateOutput();
+
+  bool Validate;
+  bool Format;
+
+  QIODevice* OutputSchema;
+  QIODevice* Transformation;
+  QIODevice* Output;
+
+  QXmlQuery XslTransform;
+  QList ExtraTransformations;
+  ctkCmdLineModuleXmlMsgHandler MsgHandler;
+
+  QString ErrorStr;
+};
+
+bool ctkCmdLineModuleXslTransformPrivate::validateOutput()
+{
+  this->ErrorStr.clear();
+
+  QIODevice* outputSchema = this->OutputSchema;
+
+  // If there is no custom schema for validating the output, we just return.
+  // The QtDesigner.xsd schema below (which should be the default) exhausts
+  // the memory during validation.
+  if (!outputSchema) return true;
+
+  QScopedPointer defaultOutputSchema(new QFile(":/QtDesigner.xsd"));
+  if (!outputSchema)
+  {
+    outputSchema = defaultOutputSchema.data();
+    outputSchema->open(QIODevice::ReadOnly);
+  }
+  outputSchema->reset();
+
+  QXmlSchema schema;
+
+  ctkCmdLineModuleXmlMsgHandler msgHandler;
+  schema.setMessageHandler(&msgHandler);
+
+  if (!schema.load(outputSchema))
+  {
+    QString msg("Invalid output schema at line %1, column %2: %3");
+    ErrorStr = msg.arg(msgHandler.line()).arg(msgHandler.column()).arg(msgHandler.statusMessage());
+    return false;
+  }
+
+  QXmlSchemaValidator validator(schema);
+  validator.setMessageHandler(&msgHandler);
+
+  if (!validator.validate(Output))
+  {
+    QString msg("Error validating transformed XML input, at line %1, column %2: %3");
+    ErrorStr = msg.arg(msgHandler.line()).arg(msgHandler.column())
+                .arg(msgHandler.statusMessage());
+    return false;
+  }
+
+  return true;
+}
+
 ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIODevice *output)
   : ctkCmdLineModuleXmlValidator(input)
-  , Validate(false)
-  , Format(false)
-  , OutputSchema(0)
-  , Transformation(0)
-  , Output(output)
-  , XslTransform(QXmlQuery::XSLT20)
-  , MsgHandler(0)
+  , d(new ctkCmdLineModuleXslTransformPrivate(output))
 {
-  this->MsgHandler = new ctkCmdLineModuleXmlMsgHandler();
-  this->XslTransform.setMessageHandler(this->MsgHandler);
-
   this->bindVariable("executableWidget", QVariant(QString("QWidget")));
   this->bindVariable("parametersWidget", QVariant(QString("ctkCollapsibleGroupBox")));
   this->bindVariable("booleanWidget", QVariant(QString("QCheckBox")));
@@ -59,47 +127,46 @@ ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIO
 
 ctkCmdLineModuleXslTransform::~ctkCmdLineModuleXslTransform()
 {
-  delete this->MsgHandler;
 }
 
 void ctkCmdLineModuleXslTransform::setOutput(QIODevice* output)
 {
-  this->Output = output;
+  d->Output = output;
 }
 
 QIODevice* ctkCmdLineModuleXslTransform::output() const
 {
-  return this->Output;
+  return d->Output;
 }
 
 void ctkCmdLineModuleXslTransform::setOutputSchema(QIODevice *output)
 {
-  this->OutputSchema = output;
+  d->OutputSchema = output;
 }
 
 bool ctkCmdLineModuleXslTransform::formatXmlOutput() const
 {
-  return this->Format;
+  return d->Format;
 }
 
 void ctkCmdLineModuleXslTransform::setFormatXmlOutput(bool format)
 {
-  this->Format = format;
+  d->Format = format;
 }
 
 bool ctkCmdLineModuleXslTransform::transform()
 {
-  this->ErrorStr.clear();
+  d->ErrorStr.clear();
 
-  if (!Output)
+  if (!d->Output)
   {
-    this->ErrorStr = "No output device set";
+    d->ErrorStr = "No output device set";
     return false;
   }
   QIODevice* inputDevice = this->input();
   if (!inputDevice)
   {
-    this->ErrorStr = "No input set for deriving an output.";
+    d->ErrorStr = "No input set for deriving an output.";
     return false;
   }
   else if (!(inputDevice->openMode() & QIODevice::ReadOnly))
@@ -109,14 +176,14 @@ bool ctkCmdLineModuleXslTransform::transform()
   inputDevice->reset();
 
 
-  if (!this->XslTransform.setFocus(inputDevice))
+  if (!d->XslTransform.setFocus(inputDevice))
   {
     QString msg("Error transforming XML input: %1");
-    this->ErrorStr = msg.arg(this->MsgHandler->statusMessage());
+    d->ErrorStr = msg.arg(d->MsgHandler.statusMessage());
     return false;
   }
 
-  QIODevice* transformation = this->Transformation;
+  QIODevice* transformation = d->Transformation;
   QScopedPointer defaultTransform(new QFile(":/ctkCmdLineModuleXmlToQtUi.xsl"));
   if (!transformation)
   {
@@ -125,7 +192,7 @@ bool ctkCmdLineModuleXslTransform::transform()
   }
   QString query(transformation->readAll());
   QString extra;
-  foreach(QIODevice* extraIODevice, this->ExtraTransformations)
+  foreach(QIODevice* extraIODevice, d->ExtraTransformations)
     {
     extraIODevice->open(QIODevice::ReadOnly);
     extra += extraIODevice->readAll();
@@ -134,61 +201,61 @@ bool ctkCmdLineModuleXslTransform::transform()
 #if 0
   qDebug() << query;
 #endif
-  this->XslTransform.setQuery(query);
+  d->XslTransform.setQuery(query);
 
   bool closeOutput = false;
-  if (!(this->Output->openMode() & QIODevice::WriteOnly))
+  if (!(d->Output->openMode() & QIODevice::WriteOnly))
   {
-    this->Output->open(QIODevice::WriteOnly);
+    d->Output->open(QIODevice::WriteOnly);
     closeOutput = true;
   }
 
   QScopedPointer xmlSerializer;
-  if (Format)
+  if (d->Format)
   {
-    xmlSerializer.reset(new QXmlFormatter(this->XslTransform, this->Output));
+    xmlSerializer.reset(new QXmlFormatter(d->XslTransform, d->Output));
   }
   else
   {
-    xmlSerializer.reset(new QXmlSerializer(this->XslTransform, this->Output));
+    xmlSerializer.reset(new QXmlSerializer(d->XslTransform, d->Output));
   }
 
-  if (!this->XslTransform.evaluateTo(xmlSerializer.data()))
+  if (!d->XslTransform.evaluateTo(xmlSerializer.data()))
   {
     QString msg("Error transforming XML input, at line %1, column %2: %3");
-    this->ErrorStr = msg.arg(this->MsgHandler->line()).arg(this->MsgHandler->column())
-      .arg(this->MsgHandler->statusMessage());
+    d->ErrorStr = msg.arg(d->MsgHandler.line()).arg(d->MsgHandler.column())
+        .arg(d->MsgHandler.statusMessage());
     return false;
   }
 
 #if 0
-  qDebug() << this->Output;
+  qDebug() << d->Output;
 #endif
 
   if (closeOutput)
   {
-    this->Output->close();
+    d->Output->close();
   }
   else
   {
-    this->Output->reset();
+    d->Output->reset();
   }
 
-  if (this->Validate)
+  if (d->Validate)
   {
-    return this->validateOutput();
+    return d->validateOutput();
   }
   return true;
 }
 
 void ctkCmdLineModuleXslTransform::setXslTransformation(QIODevice *transformation)
 {
-  this->Transformation = transformation;
+  d->Transformation = transformation;
 }
 
 void ctkCmdLineModuleXslTransform::bindVariable(const QString& name, const QVariant& value)
 {
-  this->XslTransform.bindVariable(name, value);
+  d->XslTransform.bindVariable(name, value);
 }
 
 void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transformation)
@@ -200,62 +267,17 @@ void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transfor
 
 void ctkCmdLineModuleXslTransform::setXslExtraTransformations(const QList& transformations)
 {
-  this->ExtraTransformations = transformations;
+  d->ExtraTransformations = transformations;
 }
 
 void ctkCmdLineModuleXslTransform::setValidateOutput(bool validate)
 {
-  this->Validate = validate;
-}
-
-bool ctkCmdLineModuleXslTransform::validateOutput()
-{
-  this->ErrorStr.clear();
-
-  QIODevice* outputSchema = this->OutputSchema;
-
-  // If there is no custom schema for validating the output, we just return.
-  // The QtDesigner.xsd schema below (which should be the default) exhausts
-  // the memory during validation.
-  if (!outputSchema) return true;
-
-  QScopedPointer defaultOutputSchema(new QFile(":/QtDesigner.xsd"));
-  if (!outputSchema)
-  {
-    outputSchema = defaultOutputSchema.data();
-    outputSchema->open(QIODevice::ReadOnly);
-  }
-  outputSchema->reset();
-
-  QXmlSchema schema;
-
-  ctkCmdLineModuleXmlMsgHandler msgHandler;
-  schema.setMessageHandler(&msgHandler);
-
-  if (!schema.load(outputSchema))
-  {
-    QString msg("Invalid output schema at line %1, column %2: %3");
-    ErrorStr = msg.arg(msgHandler.line()).arg(msgHandler.column()).arg(msgHandler.statusMessage());
-    return false;
-  }
-
-  QXmlSchemaValidator validator(schema);
-  validator.setMessageHandler(&msgHandler);
-
-  if (!validator.validate(Output))
-  {
-    QString msg("Error validating transformed XML input, at line %1, column %2: %3");
-    ErrorStr = msg.arg(msgHandler.line()).arg(msgHandler.column())
-                .arg(msgHandler.statusMessage());
-    return false;
-  }
-
-  return true;
+  d->Validate = validate;
 }
 
 bool ctkCmdLineModuleXslTransform::error() const
 {
-  return ctkCmdLineModuleXmlValidator::error() || !this->ErrorStr.isEmpty();
+  return ctkCmdLineModuleXmlValidator::error() || !d->ErrorStr.isEmpty();
 }
 
 QString ctkCmdLineModuleXslTransform::errorString() const
@@ -263,7 +285,7 @@ QString ctkCmdLineModuleXslTransform::errorString() const
   QString errStr = this->ctkCmdLineModuleXmlValidator::errorString();
   if (errStr.isEmpty())
   {
-    return this->ErrorStr;
+    return d->ErrorStr;
   }
   return errStr;
 }
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
index 5bca881435..11efa6dafa 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h
@@ -25,12 +25,9 @@
 // CTK includes
 #include "ctkCommandLineModulesCoreExport.h"
 #include "ctkCmdLineModuleXmlValidator.h"
-class ctkCmdLineModuleXmlMsgHandler;
+class ctkCmdLineModuleXslTransformPrivate;
 
 // Qt includes
-#include 
-#include 
-#include 
 class QIODevice;
 
 /**
@@ -116,20 +113,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform
 
 private:
 
-  bool validateOutput();
+  QScopedPointer d;
 
-  bool Validate;
-  bool Format;
-
-  QIODevice* OutputSchema;
-  QIODevice* Transformation;
-  QIODevice* Output;
-
-  QXmlQuery XslTransform;
-  QList ExtraTransformations;
-  ctkCmdLineModuleXmlMsgHandler* MsgHandler;
-
-  QString ErrorStr;
 };
 
 

From 9fb4b4729aa95840bb619d279498bb1f909700a8 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 30 Jul 2012 12:09:34 +0200
Subject: [PATCH 088/247] Use variable substitution syntax for unsupported
 widget types.

---
 .../Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl                | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
index 0c8d52668a..6f644eae7a 100644
--- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
+++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
@@ -402,7 +402,7 @@
   
     
     
-      
+      
         
           <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body><p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">Element '' not supported yet.</span></p></body></html>
         

From f1b342fc69cb022ed778a3c2e75c11bdff17226e Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Tue, 31 Jul 2012 13:01:01 -0400
Subject: [PATCH 089/247] Differentiate missing keys and previously seen keys
 in dicom tag cache

This change allows the tag cache to record when keys have been
previously accessed but were either missing from the instance or
had empty string values.  In either case, they fileValue method
should return an empty string; with this change the file does not
get re-parsed when the missing/empty value is requested subsequently.
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 0e5f276b1f..8dcbb582ef 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -62,6 +62,10 @@
 static ctkLogger logger("org.commontk.dicom.DICOMDatabase" );
 //------------------------------------------------------------------------------
 
+// Flag for tag cache to avoid repeated serarches for
+// tags that do no exist.
+static QString TagNotInInstance("__TAG_NOT_IN_INSTANCE__");
+
 //------------------------------------------------------------------------------
 class ctkDICOMDatabasePrivate
 {
@@ -676,6 +680,10 @@ QString ctkDICOMDatabase::headerValue (QString key)
 QString ctkDICOMDatabase::instanceValue(QString sopInstanceUID, QString tag)
 {
   QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value == TagNotInInstance)
+    {
+    return "";
+    }
   if (value != "")
     {
     return value;
@@ -690,6 +698,10 @@ QString ctkDICOMDatabase::instanceValue(const QString sopInstanceUID, const unsi
 {
   QString tag = this->groupElementToTag(group,element);
   QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value == TagNotInInstance)
+    {
+    return "";
+    }
   if (value != "")
     {
     return value;
@@ -714,6 +726,10 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, QString tag)
   this->tagToGroupElement(tag, group, element);
   QString sopInstanceUID = this->instanceForFile(fileName);
   QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value == TagNotInInstance)
+    {
+    return "";
+    }
   if (value != "")
     {
     return value;
@@ -740,6 +756,10 @@ QString ctkDICOMDatabase::fileValue(const QString fileName, const unsigned short
   QString tag = this->groupElementToTag(group, element);
   QString sopInstanceUID = this->instanceForFile(fileName);
   QString value = this->cachedTag(sopInstanceUID, tag);
+  if (value == TagNotInInstance)
+    {
+    return "";
+    }
   if (value != "")
     {
     return value;
@@ -1502,10 +1522,15 @@ bool ctkDICOMDatabase::cacheTag(const QString sopInstanceUID, const QString tag,
       return false;
       }
     }
+  QString valueToInsert(value);
+  if (valueToInsert == "")
+    {
+    valueToInsert = TagNotInInstance;
+    }
   QSqlQuery insertTag( d->TagCacheDatabase );
   insertTag.prepare( "INSERT OR REPLACE INTO TagCache VALUES(:sopInstanceUID, :tag, :value)" );
   insertTag.bindValue(":sopInstanceUID",sopInstanceUID);
   insertTag.bindValue(":tag",tag);
-  insertTag.bindValue(":value",value);
+  insertTag.bindValue(":value",valueToInsert);
   return d->loggedExec(insertTag);
 }

From b42792c7071d96a07b6ccdaa9fcbb8e465d52a54 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Wed, 1 Aug 2012 15:14:37 -0400
Subject: [PATCH 090/247] Add tests for tag cache and precaching in dicom
 database

Test to ensure that requested precache tags are included
in the tag cache during import operations and that correct values
are returned when asking for valid and invalid cache values.
---
 Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt    |   2 +
 .../Testing/Cpp/ctkDICOMDatabaseTest4.cpp     | 132 ++++++++++++++++++
 2 files changed, 134 insertions(+)
 create mode 100644 Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest4.cpp

diff --git a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
index ef2ff20292..c2bdba55ac 100644
--- a/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
+++ b/Libs/DICOM/Core/Testing/Cpp/CMakeLists.txt
@@ -5,6 +5,7 @@ create_test_sourcelist(Tests ${KIT}CppTests.cpp
   ctkDICOMDatabaseTest1.cpp
   ctkDICOMDatabaseTest2.cpp
   ctkDICOMDatabaseTest3.cpp
+  ctkDICOMDatabaseTest4.cpp
   ctkDICOMDatasetTest1.cpp
   ctkDICOMIndexerTest1.cpp
   ctkDICOMModelTest1.cpp
@@ -35,6 +36,7 @@ SIMPLE_TEST(ctkDICOMDatabaseTest2 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)
 SIMPLE_TEST(ctkDICOMDatabaseTest3
   ${CMAKE_CURRENT_SOURCE_DIR}/../../Resources/dicom-unversioned-schema.sql
   )
+SIMPLE_TEST(ctkDICOMDatabaseTest4 ${CTKData_DIR}/Data/DICOM/MRHEAD/000055.IMA)
 SIMPLE_TEST(ctkDICOMDatasetTest1)
 SIMPLE_TEST(ctkDICOMIndexerTest1 )
 
diff --git a/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest4.cpp b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest4.cpp
new file mode 100644
index 0000000000..875fa4d9c0
--- /dev/null
+++ b/Libs/DICOM/Core/Testing/Cpp/ctkDICOMDatabaseTest4.cpp
@@ -0,0 +1,132 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  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.
+
+=========================================================================*/
+
+// Qt includes
+#include 
+#include 
+
+// ctkDICOMCore includes
+#include "ctkDICOMDatabase.h"
+
+// STD includes
+#include 
+#include 
+
+
+int ctkDICOMDatabaseTest4( int argc, char * argv [] )
+{
+  QCoreApplication app(argc, argv);
+
+  if (argc < 2)
+    {
+    std::cerr << "ctkDICOMDatabaseTest2: missing dicom filePath argument";
+    std::cerr << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  QString dicomFilePath(argv[1]);
+
+  ctkDICOMDatabase database;
+  QDir databaseDirectory = QDir::temp();
+  databaseDirectory.remove("ctkDICOMDatabase.sql");
+  databaseDirectory.remove("ctkDICOMTagCache.sql");
+
+  QFileInfo databaseFile(databaseDirectory, QString("database.test"));
+  database.openDatabase(databaseFile.absoluteFilePath());
+
+  bool res = database.initializeDatabase();
+
+  if (!res)
+    {
+    std::cerr << "ctkDICOMDatabase::initializeDatabase() failed." << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  //
+  // Basic test:
+  // - insert the file specified on the command line
+  // - ask for tag values and compare to known results
+  //
+  QString instanceUID("1.2.840.113619.2.135.3596.6358736.4843.1115808177.83");
+  QString tag("0008,103e");
+  QString badTag("9999,9999");
+
+  //
+  // Test the precache feature of the database
+  //
+
+  if (database.cachedTag(instanceUID, tag) != QString(""))
+    {
+    std::cerr << "ctkDICOMDatabase: tag cache should return empty string for unknown instance tag" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (database.cachedTag(instanceUID, badTag) != QString(""))
+    {
+    std::cerr << "ctkDICOMDatabase: bad tag cache should return empty string for unknown instance tag" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  QStringList tagsToPrecache;
+  tagsToPrecache << tag;
+  database.setTagsToPrecache(tagsToPrecache);
+
+  if (database.tagsToPrecache() != tagsToPrecache)
+    {
+    std::cerr << "ctkDICOMDatabase: tags to precache not correct" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  database.insert(dicomFilePath, false, false);
+
+  QString knownSeriesDescription("3D Cor T1 FAST IR-prepped GRE");
+  
+  QString cachedTag = database.cachedTag(instanceUID, tag);
+
+  if (cachedTag != knownSeriesDescription)
+    {
+    std::cerr << "ctkDICOMDatabase: tag cache should return known value for instance" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (database.instanceValue(instanceUID, tag) != knownSeriesDescription)
+    {
+    std::cerr << "ctkDICOMDatabase: database should return known value for instance" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (database.instanceValue(instanceUID, badTag) != QString(""))
+    {
+    std::cerr << "ctkDICOMDatabase: bad tag should have empty value" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  if (database.cachedTag(instanceUID, badTag) != QString("__TAG_NOT_IN_INSTANCE__"))
+    {
+    std::cerr << "ctkDICOMDatabase: bad tag should have sentinal value in cache" << std::endl;
+    return EXIT_FAILURE;
+    }
+
+  database.closeDatabase();
+
+  std::cerr << "Database is in " << databaseDirectory.path().toStdString() << std::endl;
+
+  return EXIT_SUCCESS;
+}

From 03a982743701fb96c88893e12ea865ec075fa6a9 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Wed, 1 Aug 2012 15:32:47 -0400
Subject: [PATCH 091/247] Avoid assert on ill-formed group/element strings

---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 8dcbb582ef..f80f9c0524 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -780,6 +780,10 @@ bool ctkDICOMDatabase::tagToGroupElement(const QString tag, unsigned short& grou
 {
   QStringList groupElement = tag.split(",");
   bool groupOK, elementOK;
+  if (groupElement.length() != 2)
+    {
+    return false;
+    }
   group = groupElement[0].toUInt(&groupOK, 16);
   element = groupElement[1].toUInt(&elementOK, 16);
 

From 851d7e7e078f27b5a7d626fcddcfe9dc37b21807 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Wed, 1 Aug 2012 18:11:37 -0400
Subject: [PATCH 092/247] Expose tags to precache in app widget for use with
 private database

Since applications cannot directly manipulate the database of the
app widget, we expose a property and delegate it to the
privare database.
---
 Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp | 16 ++++++++++++++++
 Libs/DICOM/Widgets/ctkDICOMAppWidget.h   |  9 +++++++++
 2 files changed, 25 insertions(+)

diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
index 9c822f1713..b85fc8ed30 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
@@ -296,6 +296,22 @@ bool ctkDICOMAppWidget::searchWidgetPopUpMode(){
   return d->IsSearchWidgetPopUpMode;
 }
 
+//------------------------------------------------------------------------------
+void ctkDICOMAppWidget::setTagsToPrecache( const QStringList tags)
+{
+  Q_D(ctkDICOMAppWidget);
+  d->DICOMDatabase->setTagsToPrecache(tags);
+}
+
+//------------------------------------------------------------------------------
+const QStringList ctkDICOMAppWidget::tagsToPrecache()
+{
+  Q_D(ctkDICOMAppWidget);
+  return d->DICOMDatabase->tagsToPrecache();
+}
+
+
+
 //----------------------------------------------------------------------------
 void ctkDICOMAppWidget::setSearchWidgetPopUpMode(bool flag){
   Q_D(ctkDICOMAppWidget);
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
index 0fb40f0675..f20ba2dfd0 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
@@ -36,14 +36,23 @@ class CTK_DICOM_WIDGETS_EXPORT ctkDICOMAppWidget : public QWidget
   Q_OBJECT
   Q_PROPERTY(QString databaseDirectory READ databaseDirectory WRITE setDatabaseDirectory)
   Q_PROPERTY(bool searchWidgetPopUpMode READ searchWidgetPopUpMode WRITE setSearchWidgetPopUpMode)
+  Q_PROPERTY(QStringList tagsToPrecache READ tagsToPrecache WRITE setTagsToPrecache)
 
 public:
   typedef QWidget Superclass;
   explicit ctkDICOMAppWidget(QWidget* parent=0);
   virtual ~ctkDICOMAppWidget();
 
+  /// Directory being used to store the dicom database
   QString databaseDirectory() const;
 
+  /// See ctkDICOMDatabase for description - these accessors
+  /// delegate to the corresponding routines of the internal
+  /// instance of the database.
+  /// @see ctkDICOMDatabase
+  void setTagsToPrecache(const QStringList tags);
+  const QStringList tagsToPrecache();
+
   /// Updates schema of loaded database to match the one
   /// coded by the current version of ctkDICOMDatabase.
   /// Also provides a dialog box for progress

From 1cb4c934a7136347972496c92a940347cd0acc87 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Thu, 2 Aug 2012 16:12:53 -0400
Subject: [PATCH 093/247] Precache all tags with a single load of the dataset

This change avoids doing a new load of the dataset for each tag
in the precache list.
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index f80f9c0524..b58bb0a567 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -1029,9 +1029,18 @@ const QStringList ctkDICOMDatabase::tagsToPrecache()
 void ctkDICOMDatabasePrivate::precacheTags( const QString sopInstanceUID )
 {
   Q_Q(ctkDICOMDatabase);
+
+  ctkDICOMDataset dataset;
+  QString fileName = q->fileForInstance(sopInstanceUID);
+  dataset.InitializeFromFile(fileName);
+
   foreach (const QString &tag, this->TagsToPrecache)
     {
-    q->instanceValue(sopInstanceUID, tag);
+    unsigned short group, element;
+    q->tagToGroupElement(tag, group, element);
+    DcmTagKey tagKey(group, element);
+    QString value = dataset.GetAllElementValuesAsString(tagKey);
+    q->cacheTag(sopInstanceUID, tag, value);
     }
 }
 

From 76b69a0202bd421b6d1be966ffed605e571e05bc Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 3 Aug 2012 13:06:13 -0400
Subject: [PATCH 094/247] Add indices that will speed up common query scenarios

See issue #225
---
 Libs/DICOM/Core/Resources/dicom-schema.sql | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index 368990d2cc..5df19e9e02 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -14,6 +14,9 @@ DROP TABLE IF EXISTS 'Studies' ;
 DROP TABLE IF EXISTS 'Directories' ;
 
 DROP INDEX IF EXISTS 'ImagesFilenameIndex' ;
+DROP INDEX IF EXISTS 'ImagesSeriesIndex' ;
+DROP INDEX IF EXISTS 'SeriesStudyIndex' ;
+DROP INDEX IF EXISTS 'StudiesPatientIndex' ;
 
 CREATE TABLE 'SchemaInfo' ( 'Version' VARCHAR(1024) NOT NULL );
 INSERT INTO 'SchemaInfo' VALUES('0.5.1');
@@ -64,6 +67,9 @@ CREATE TABLE 'Studies' (
   PRIMARY KEY ('StudyInstanceUID') );
 
 CREATE UNIQUE INDEX IF NOT EXISTS 'ImagesFilenameIndex' ON 'Images' ('Filename');
+CREATE UNIQUE INDEX IF NOT EXISTS 'ImagesSeriesIndex' ON 'Images' ('SeriesInstanceUID');
+CREATE UNIQUE INDEX IF NOT EXISTS 'SeriesStudyIndex' ON 'Series' ('StudyInstanceUID');
+CREATE UNIQUE INDEX IF NOT EXISTS 'StudiesPatientIndex' ON 'Studies' ('PatientsUID');
 
 CREATE TABLE 'Directories' (
   'Dirname' VARCHAR(1024) ,

From bc02c1b2af8b0af32b8484fa356a83758c04bfbe Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 3 Aug 2012 13:07:27 -0400
Subject: [PATCH 095/247] Update schema number to account for new indices

---
 Libs/DICOM/Core/Resources/dicom-schema.sql | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index 5df19e9e02..f8b196df8c 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -19,7 +19,7 @@ DROP INDEX IF EXISTS 'SeriesStudyIndex' ;
 DROP INDEX IF EXISTS 'StudiesPatientIndex' ;
 
 CREATE TABLE 'SchemaInfo' ( 'Version' VARCHAR(1024) NOT NULL );
-INSERT INTO 'SchemaInfo' VALUES('0.5.1');
+INSERT INTO 'SchemaInfo' VALUES('0.5.2');
 
 CREATE TABLE 'Images' (
   'SOPInstanceUID' VARCHAR(64) NOT NULL,

From 2ad2f8f19a2448cbc253981424c0f2f4ddc9ff9a Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 3 Aug 2012 16:47:00 -0400
Subject: [PATCH 096/247] Make progress dialogs into member variables.

Closes #223
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp     |   7 +-
 Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp | 223 ++++++++++++++---------
 Libs/DICOM/Widgets/ctkDICOMAppWidget.h   |   2 -
 3 files changed, 139 insertions(+), 93 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index f80f9c0524..9dcb147c4a 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -458,7 +458,12 @@ bool ctkDICOMDatabase::updateSchemaIfNeeded(const char* schemaFile)
     {
     return this->updateSchema(schemaFile);
     }
-  return false;
+  else
+    {
+    emit schemaUpdateStarted(0);
+    emit schemaUpdated();
+    return false;
+    }
 }
 
 //------------------------------------------------------------------------------
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
index b85fc8ed30..a4038c0974 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.cpp
@@ -71,6 +71,7 @@ class ctkDICOMAppWidgetPrivate: public Ui_ctkDICOMAppWidget
   Q_DECLARE_PUBLIC(ctkDICOMAppWidget);
 
   ctkDICOMAppWidgetPrivate(ctkDICOMAppWidget* );
+  ~ctkDICOMAppWidgetPrivate();
 
   ctkFileDialog* ImportDialog;
   ctkDICOMQueryRetrieveWidget* QueryRetrieveWidget;
@@ -80,6 +81,11 @@ class ctkDICOMAppWidgetPrivate: public Ui_ctkDICOMAppWidget
   ctkDICOMModel DICOMModel;
   ctkDICOMFilterProxyModel DICOMProxyModel;
   QSharedPointer DICOMIndexer;
+  QProgressDialog *IndexerProgress;
+  QProgressDialog *UpdateSchemaProgress;
+
+  void showIndexerDialog();
+  void showUpdateSchemaDialog();
 
   // used when suspending the ctkDICOMModel
   QSqlDatabase EmptyDatabase;
@@ -97,16 +103,131 @@ ctkDICOMAppWidgetPrivate::ctkDICOMAppWidgetPrivate(ctkDICOMAppWidget* parent): q
   ThumbnailGenerator = QSharedPointer  (new ctkDICOMThumbnailGenerator);
   DICOMDatabase->setThumbnailGenerator(ThumbnailGenerator.data());
   DICOMIndexer = QSharedPointer (new ctkDICOMIndexer);
+  IndexerProgress = 0;
+  UpdateSchemaProgress = 0;
+}
+
+ctkDICOMAppWidgetPrivate::~ctkDICOMAppWidgetPrivate()
+{
+  if ( IndexerProgress )
+    {
+    delete IndexerProgress;
+    }
+  if ( UpdateSchemaProgress )
+    {
+    delete UpdateSchemaProgress;
+    }
+}
+
+void ctkDICOMAppWidgetPrivate::showUpdateSchemaDialog()
+{
+  Q_Q(ctkDICOMAppWidget);
+  if (UpdateSchemaProgress == 0)
+    {
+    //
+    // Set up the Update Schema Progress Dialog
+    //
+    UpdateSchemaProgress = new QProgressDialog(
+        q->tr("DICOM Schema Update"), "Cancel", 0, 100, q,
+         Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+
+    // We don't want the progress dialog to resize itself, so we bypass the label
+    // by creating our own
+    QLabel* progressLabel = new QLabel(q->tr("Initialization..."));
+    UpdateSchemaProgress->setLabel(progressLabel);
+#ifdef Q_WS_MAC
+    // BUG: avoid deadlock of dialogs on mac
+    UpdateSchemaProgress->setWindowModality(Qt::NonModal);
+#else
+    UpdateSchemaProgress->setWindowModality(Qt::ApplicationModal);
+#endif
+    UpdateSchemaProgress->setMinimumDuration(0);
+    UpdateSchemaProgress->setValue(0);
+
+    //q->connect(UpdateSchemaProgress, SIGNAL(canceled()), 
+     //       DICOMIndexer.data(), SLOT(cancel()));
+
+    q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateStarted(int)),
+            UpdateSchemaProgress, SLOT(setMaximum(int)));
+    q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(int)),
+            UpdateSchemaProgress, SLOT(setValue(int)));
+    q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(QString)),
+            progressLabel, SLOT(setText(QString)));
+
+    // close the dialog
+    q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdated()),
+            UpdateSchemaProgress, SLOT(close()));
+    // reset the database to show new data
+    q->connect(DICOMDatabase.data(), SIGNAL(schemaUpdated()),
+            &DICOMModel, SLOT(reset()));
+    // reset the database if canceled
+    q->connect(UpdateSchemaProgress, SIGNAL(canceled()), 
+            &DICOMModel, SLOT(reset()));
+    }
+  UpdateSchemaProgress->show();
+}
+
+void ctkDICOMAppWidgetPrivate::showIndexerDialog()
+{
+  Q_Q(ctkDICOMAppWidget);
+  if (IndexerProgress == 0)
+    {
+    //
+    // Set up the Indexer Progress Dialog
+    //
+    IndexerProgress = new QProgressDialog( q->tr("DICOM Import"), "Cancel", 0, 100, q,
+         Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
+
+    // We don't want the progress dialog to resize itself, so we bypass the label
+    // by creating our own
+    QLabel* progressLabel = new QLabel(q->tr("Initialization..."));
+    IndexerProgress->setLabel(progressLabel);
+#ifdef Q_WS_MAC
+    // BUG: avoid deadlock of dialogs on mac
+    IndexerProgress->setWindowModality(Qt::NonModal);
+#else
+    IndexerProgress->setWindowModality(Qt::ApplicationModal);
+#endif
+    IndexerProgress->setMinimumDuration(0);
+    IndexerProgress->setValue(0);
+
+    q->connect(IndexerProgress, SIGNAL(canceled()), 
+                 DICOMIndexer.data(), SLOT(cancel()));
+
+    q->connect(DICOMIndexer.data(), SIGNAL(progress(int)),
+            IndexerProgress, SLOT(setValue(int)));
+    q->connect(DICOMIndexer.data(), SIGNAL(indexingFilePath(QString)),
+            progressLabel, SLOT(setText(QString)));
+
+    // close the dialog
+    q->connect(DICOMIndexer.data(), SIGNAL(indexingComplete()),
+            IndexerProgress, SLOT(close()));
+    // reset the database to show new data
+    q->connect(DICOMIndexer.data(), SIGNAL(indexingComplete()),
+            &DICOMModel, SLOT(reset()));
+    // stop indexing and reset the database if canceled
+    q->connect(IndexerProgress, SIGNAL(canceled()), 
+            DICOMIndexer.data(), SLOT(cancel()));
+    q->connect(IndexerProgress, SIGNAL(canceled()), 
+            &DICOMModel, SLOT(reset()));
+
+    // allow users of this widget to know that the process has finished
+    q->connect(IndexerProgress, SIGNAL(canceled()), 
+            q, SIGNAL(directoryImported()));
+    q->connect(DICOMIndexer.data(), SIGNAL(indexingComplete()),
+            q, SIGNAL(directoryImported()));
+    }
+  IndexerProgress->show();
 }
 
 //----------------------------------------------------------------------------
 // ctkDICOMAppWidget methods
 
 //----------------------------------------------------------------------------
-ctkDICOMAppWidget::ctkDICOMAppWidget(QWidget* _parent):Superclass(_parent), 
+ctkDICOMAppWidget::ctkDICOMAppWidget(QWidget* _parent):Superclass(_parent),
     d_ptr(new ctkDICOMAppWidgetPrivate(this))
 {
-  Q_D(ctkDICOMAppWidget);  
+  Q_D(ctkDICOMAppWidget);
 
   d->setupUi(this);
 
@@ -186,7 +307,7 @@ ctkDICOMAppWidget::ctkDICOMAppWidget(QWidget* _parent):Superclass(_parent),
 //----------------------------------------------------------------------------
 ctkDICOMAppWidget::~ctkDICOMAppWidget()
 {
-  Q_D(ctkDICOMAppWidget);  
+  Q_D(ctkDICOMAppWidget);
 
   d->QueryRetrieveWidget->deleteLater();
   d->ImportDialog->deleteLater();
@@ -196,54 +317,16 @@ ctkDICOMAppWidget::~ctkDICOMAppWidget()
 void ctkDICOMAppWidget::updateDatabaseSchemaIfNeeded()
 {
 
-  Q_D(ctkDICOMAppWidget);  
-
-  if ( d->DICOMDatabase->schemaVersion() != d->DICOMDatabase->schemaVersionLoaded() )
-    {
-    QProgressDialog* progress = new QProgressDialog("DICOM Schema Update", "Cancel", 0, 100, this,
-                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
-    // We don't want the progress dialog to resize itself, so we bypass the label
-    // by creating our own
-    QLabel* progressLabel = new QLabel(tr("Initialization..."));
-    progress->setLabel(progressLabel);
-#ifdef Q_WS_MAC
-    // BUG: avoid deadlock of dialogs on mac
-    progress->setWindowModality(Qt::NonModal);
-#else
-    progress->setWindowModality(Qt::ApplicationModal);
-#endif
-    progress->setMinimumDuration(0);
-    progress->setValue(0);
-    progress->show();
-
-    // TODO - cancel?
-    //connect(progress, SIGNAL(canceled()), d->DICOMIndexer.data(), SLOT(cancel()));
-
-    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateStarted(int)),
-            progress, SLOT(setMaximum(int)));
-    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(int)),
-            progress, SLOT(setValue(int)));
-    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdateProgress(QString)),
-            progressLabel, SLOT(setText(QString)));
-    connect(d->DICOMDatabase.data(), SIGNAL(progress(int)),
-            this, SLOT(onProgress(int)));
-
-    // close the dialog
-    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdated()),
-            progress, SLOT(close()));
-    // reset the database to show new data
-    connect(d->DICOMDatabase.data(), SIGNAL(schemaUpdated()),
-            &d->DICOMModel, SLOT(reset()));
-
-    d->DICOMDatabase->updateSchema();
-    }
+  Q_D(ctkDICOMAppWidget);
 
+  d->showUpdateSchemaDialog();
+  d->DICOMDatabase->updateSchemaIfNeeded();
 }
 
 //----------------------------------------------------------------------------
 void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
 {
-  Q_D(ctkDICOMAppWidget);  
+  Q_D(ctkDICOMAppWidget);
 
   QSettings settings;
   settings.setValue("DatabaseDirectory", directory);
@@ -251,7 +334,7 @@ void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
 
   //close the active DICOM database
   d->DICOMDatabase->closeDatabase();
-  
+
   //open DICOM database on the directory
   QString databaseFileName = directory + QString("/ctkDICOM.sql");
   try
@@ -267,7 +350,7 @@ void ctkDICOMAppWidget::setDatabaseDirectory(const QString& directory)
 
   // update the database schema if needed and provide progress
   this->updateDatabaseSchemaIfNeeded();
-  
+
   d->DICOMModel.setDatabase(d->DICOMDatabase->database());
   d->DICOMModel.setEndLevel(ctkDICOMModel::SeriesType);
   d->TreeView->resizeColumnToContents(0);
@@ -350,7 +433,7 @@ void ctkDICOMAppWidget::onAddToDatabase()
 void ctkDICOMAppWidget::openImportDialog()
 {
   Q_D(ctkDICOMAppWidget);
-  
+
   d->ImportDialog->show();
   d->ImportDialog->raise();
 }
@@ -397,7 +480,7 @@ void ctkDICOMAppWidget::onRemoveAction()
     {
       QString seriesUID = d->DICOMModel.data(index0,ctkDICOMModel::UIDRole).toString();
       d->DICOMDatabase->removeSeries(seriesUID);
-    } 
+    }
     else if ( d->DICOMModel.data(index0,ctkDICOMModel::TypeRole) == static_cast(ctkDICOMModel::StudyType))
     {
       QString studyUID = d->DICOMModel.data(index0,ctkDICOMModel::UIDRole).toString();
@@ -436,13 +519,6 @@ void ctkDICOMAppWidget::resetModel()
   d->DICOMModel.reset();
 }
 
-//----------------------------------------------------------------------------
-void ctkDICOMAppWidget::onProgress(int progress)
-{
-  Q_UNUSED(progress);
-  QApplication::processEvents();
-}
-
 //----------------------------------------------------------------------------
 void ctkDICOMAppWidget::onThumbnailSelected(const ctkThumbnailLabel& widget)
 {
@@ -491,40 +567,7 @@ void ctkDICOMAppWidget::onImportDirectory(QString directory)
       {
       targetDirectory = d->DICOMDatabase->databaseDirectory();
       }
-    QProgressDialog* progress = new QProgressDialog("DICOM Import", "Cancel", 0, 100, this,
-                           Qt::WindowTitleHint | Qt::WindowSystemMenuHint);
-    // We don't want the progress dialog to resize itself, so we bypass the label
-    // by creating our own
-    QLabel* progressLabel = new QLabel(tr("Initialization..."));
-    progress->setLabel(progressLabel);
-#ifdef Q_WS_MAC
-    // BUG: avoid deadlock of dialogs on mac
-    progress->setWindowModality(Qt::NonModal);
-#else
-    progress->setWindowModality(Qt::ApplicationModal);
-#endif
-    progress->setMinimumDuration(0);
-    progress->setValue(0);
-    progress->show();
-
-    connect(progress, SIGNAL(canceled()), d->DICOMIndexer.data(), SLOT(cancel()));
-    connect(d->DICOMIndexer.data(), SIGNAL(indexingFilePath(QString)),
-            progressLabel, SLOT(setText(QString)));
-    connect(d->DICOMIndexer.data(), SIGNAL(progress(int)),
-            progress, SLOT(setValue(int)));
-    connect(d->DICOMIndexer.data(), SIGNAL(progress(int)),
-            this, SLOT(onProgress(int)));
-
-    // close the dialog
-    connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
-            progress, SLOT(close()));
-    // reset the database to show new data
-    connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
-            &d->DICOMModel, SLOT(reset()));
-    // allow users of this widget to know that the process has finished
-    connect(d->DICOMIndexer.data(), SIGNAL(indexingComplete()),
-            this, SIGNAL(directoryImported()));
-
+    d->showIndexerDialog();
     d->DICOMIndexer->addDirectory(*d->DICOMDatabase,directory,targetDirectory);
   }
 }
diff --git a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
index f20ba2dfd0..5f8f099751 100644
--- a/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
+++ b/Libs/DICOM/Widgets/ctkDICOMAppWidget.h
@@ -77,8 +77,6 @@ public Q_SLOTS:
   void resumeModel();
   void resetModel();
 
-  void onProgress(int);
-
 Q_SIGNALS:
   /// Emited when directory is changed
   void databaseDirectoryChanged(const QString&);

From 23c0a8751e0be8ba0fa38ea96ba420cffee993e2 Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 3 Aug 2012 17:56:33 -0400
Subject: [PATCH 097/247] Fix schema number

Database code should always be in sync with the version
of the schema.  This is checked by ctkDICOMDatabaseTest3.

Closes #226
---
 Libs/DICOM/Core/ctkDICOMDatabase.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index df42e4c533..143e629382 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -448,7 +448,7 @@ QString ctkDICOMDatabase::schemaVersion()
   //   so that the ctkDICOMDatabasePrivate::filenames method
   //   still works.
   //
-  return QString("0.5.1");
+  return QString("0.5.2");
 };
 
 //------------------------------------------------------------------------------

From 6960f701892394c3951a901ce064d736a428287c Mon Sep 17 00:00:00 2001
From: Steve Pieper 
Date: Fri, 3 Aug 2012 20:26:12 -0400
Subject: [PATCH 098/247] Fix schema error that led to only a single file per
 series

Drop the UNIQUE qualifier from some of the indices.
---
 Libs/DICOM/Core/Resources/dicom-schema.sql | 10 ++++++----
 Libs/DICOM/Core/ctkDICOMDatabase.cpp       |  2 +-
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/Libs/DICOM/Core/Resources/dicom-schema.sql b/Libs/DICOM/Core/Resources/dicom-schema.sql
index f8b196df8c..6faa7b53ce 100644
--- a/Libs/DICOM/Core/Resources/dicom-schema.sql
+++ b/Libs/DICOM/Core/Resources/dicom-schema.sql
@@ -4,6 +4,8 @@
 -- Note: the semicolon at the end is necessary for the simple parser to separate
 --       the statements since the SQlite driver does not handle multiple
 --       commands per QSqlQuery::exec call!
+-- Note: be sure to update ctkDICOMDatabase and SchemaInfo Version 
+--       whenever you make a change to this schema
 -- ;
 
 DROP TABLE IF EXISTS 'SchemaInfo' ;
@@ -19,7 +21,7 @@ DROP INDEX IF EXISTS 'SeriesStudyIndex' ;
 DROP INDEX IF EXISTS 'StudiesPatientIndex' ;
 
 CREATE TABLE 'SchemaInfo' ( 'Version' VARCHAR(1024) NOT NULL );
-INSERT INTO 'SchemaInfo' VALUES('0.5.2');
+INSERT INTO 'SchemaInfo' VALUES('0.5.3');
 
 CREATE TABLE 'Images' (
   'SOPInstanceUID' VARCHAR(64) NOT NULL,
@@ -67,9 +69,9 @@ CREATE TABLE 'Studies' (
   PRIMARY KEY ('StudyInstanceUID') );
 
 CREATE UNIQUE INDEX IF NOT EXISTS 'ImagesFilenameIndex' ON 'Images' ('Filename');
-CREATE UNIQUE INDEX IF NOT EXISTS 'ImagesSeriesIndex' ON 'Images' ('SeriesInstanceUID');
-CREATE UNIQUE INDEX IF NOT EXISTS 'SeriesStudyIndex' ON 'Series' ('StudyInstanceUID');
-CREATE UNIQUE INDEX IF NOT EXISTS 'StudiesPatientIndex' ON 'Studies' ('PatientsUID');
+CREATE INDEX IF NOT EXISTS 'ImagesSeriesIndex' ON 'Images' ('SeriesInstanceUID');
+CREATE INDEX IF NOT EXISTS 'SeriesStudyIndex' ON 'Series' ('StudyInstanceUID');
+CREATE INDEX IF NOT EXISTS 'StudiesPatientIndex' ON 'Studies' ('PatientsUID');
 
 CREATE TABLE 'Directories' (
   'Dirname' VARCHAR(1024) ,
diff --git a/Libs/DICOM/Core/ctkDICOMDatabase.cpp b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
index 143e629382..610004bcfd 100644
--- a/Libs/DICOM/Core/ctkDICOMDatabase.cpp
+++ b/Libs/DICOM/Core/ctkDICOMDatabase.cpp
@@ -448,7 +448,7 @@ QString ctkDICOMDatabase::schemaVersion()
   //   so that the ctkDICOMDatabasePrivate::filenames method
   //   still works.
   //
-  return QString("0.5.2");
+  return QString("0.5.3");
 };
 
 //------------------------------------------------------------------------------

From 9d1a13c9a59526dd4d4633e90c7f6a541264a446 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 6 Aug 2012 12:02:34 +0200
Subject: [PATCH 099/247] Register ctkCmdLineModuleReference with the Qt
 metaobject system.

---
 Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h
index a39d9f5e7b..d2fc07db7b 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h
@@ -25,6 +25,7 @@
 #include 
 
 #include 
+#include 
 
 class ctkCmdLineModuleDescription;
 class ctkCmdLineModuleReferencePrivate;
@@ -58,4 +59,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference
 
 };
 
+Q_DECLARE_METATYPE(ctkCmdLineModuleReference)
+
 #endif // CTKCMDLINEMODULEREFERENCE_H

From 68187396c96d3a6e0206b4f7ff926e76d4cf6c66 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 6 Aug 2012 12:03:51 +0200
Subject: [PATCH 100/247] Use the same name for signals as for the
 corresponding methods.

---
 Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
index 426f4abf2c..9bca0e3a52 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
@@ -74,8 +74,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
 
 Q_SIGNALS:
 
-  void moduleAdded(const ctkCmdLineModuleReference);
-  void moduleRemoved(const ctkCmdLineModuleReference);
+  void moduleRegistered(const ctkCmdLineModuleReference&);
+  void moduleUnregistered(const ctkCmdLineModuleReference&);
 
 private:
 

From 0a66f92ea13b5e38e254a6f0be6cbe0f75849c72 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 6 Aug 2012 12:05:04 +0200
Subject: [PATCH 101/247] Use descriptive names for member variables.

---
 .../Core/ctkCmdLineModuleManager.cpp          | 21 +++++++------------
 .../Core/ctkCmdLineModuleManager.h            |  2 --
 2 files changed, 8 insertions(+), 15 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
index d2452f674b..6246ea1d78 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp
@@ -42,7 +42,8 @@ struct ctkCmdLineModuleManagerPrivate
 
   ctkCmdLineModuleFactory* InstanceFactory;
 
-  QHash Cache;
+  QHash LocationToRef;
+
   bool Verbose;
 };
 
@@ -105,26 +106,26 @@ ctkCmdLineModuleManager::registerModule(const QString& location)
 
   ref.d->RawXmlDescription = xml;
 
-  d->Cache[location] = ref;
+  d->LocationToRef[location] = ref;
 
-  emit moduleAdded(ref);
+  emit moduleRegistered(ref);
   return ref;
 }
 
 void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref)
 {
-  d->Cache.remove(ref.location());
-  emit moduleRemoved(ref);
+  d->LocationToRef.remove(ref.location());
+  emit moduleUnregistered(ref);
 }
 
 ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QString& location) const
 {
-  return d->Cache[location];
+  return d->LocationToRef[location];
 }
 
 QList ctkCmdLineModuleManager::moduleReferences() const
 {
-  return d->Cache.values();
+  return d->LocationToRef.values();
 }
 
 ctkCmdLineModule*
@@ -132,9 +133,3 @@ ctkCmdLineModuleManager::createModule(const ctkCmdLineModuleReference& moduleRef
 {
   return d->InstanceFactory->create(moduleRef);
 }
-
-QList
-ctkCmdLineModuleManager::modules(const ctkCmdLineModuleReference& moduleRef) const
-{
-  throw ctkException("not implemented yet");
-}
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
index 9bca0e3a52..beef55cc23 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h
@@ -70,8 +70,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject
 
   ctkCmdLineModule* createModule(const ctkCmdLineModuleReference& moduleRef);
 
-  QList modules(const ctkCmdLineModuleReference& moduleRef) const;
-
 Q_SIGNALS:
 
   void moduleRegistered(const ctkCmdLineModuleReference&);

From 736b3a4af746f89d90d3e852e8016d79230b20f4 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 6 Aug 2012 12:32:49 +0200
Subject: [PATCH 102/247] Provide methods for querying the current module
 state.

---
 .../Core/ctkCmdLineModule.cpp                 | 19 ++++++++++++++++++-
 .../Core/ctkCmdLineModule.h                   |  5 +++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
index a8dbbe8f2d..e3f0e45b3d 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
@@ -51,6 +51,8 @@ struct ctkCmdLineModulePrivate
 
   QList ParameterNames;
 
+  ctkCmdLineModuleFuture Future;
+
 private:
 
   ctkCmdLineModule* q;
@@ -161,9 +163,24 @@ ctkCmdLineModuleFuture ctkCmdLineModule::run() const
   // thread pool.
   ctkCmdLineModuleProcessTask* moduleProcess =
       new ctkCmdLineModuleProcessTask(d->ModuleReference.location(), args);
-  return moduleProcess->start();
+  d->Future = moduleProcess->start();
+  return d->Future;
 }
 
+ctkCmdLineModuleFuture ctkCmdLineModule::future() const
+{
+  return d->Future;
+}
+
+bool ctkCmdLineModule::isRunning() const
+{
+  return d->Future.isRunning();
+}
+
+bool ctkCmdLineModule::isPaused() const
+{
+  return d->Future.isPaused();
+}
 
 QHash ctkCmdLineModule::values() const
 {
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.h b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
index c090ba6a81..14a84b91c0 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.h
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.h
@@ -62,6 +62,11 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModule : public QObject
 
   ctkCmdLineModuleFuture run() const;
 
+  ctkCmdLineModuleFuture future() const;
+
+  bool isRunning() const;
+  bool isPaused() const;
+
   Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value);
 
 protected:

From f74e11b4e94d18b405b3ae5644cb7ebfddc52bf2 Mon Sep 17 00:00:00 2001
From: Michael Bauer 
Date: Wed, 8 Aug 2012 16:38:11 +0200
Subject: [PATCH 103/247] Indexer import improvements

  - added method addListOfFiles:
    Starts importing file lists.
    In multithreaded szenarios the import is processed like a queue.

  - added addDicomdir:
    Uses DcmDicomDir to iterate through containing valid records and writes the instance file path into a list and calls addListOfFiles.

  - changed addDirectory:
    Uses QDirIterator instead of OFList. Processes files only and calls addListOfFiles.
---
 Libs/DICOM/Core/ctkDICOMIndexer.cpp | 128 ++++++++++++++++++++--------
 Libs/DICOM/Core/ctkDICOMIndexer.h   |  19 +++++
 2 files changed, 110 insertions(+), 37 deletions(-)

diff --git a/Libs/DICOM/Core/ctkDICOMIndexer.cpp b/Libs/DICOM/Core/ctkDICOMIndexer.cpp
index 492cb0a3e0..4c9ad34375 100644
--- a/Libs/DICOM/Core/ctkDICOMIndexer.cpp
+++ b/Libs/DICOM/Core/ctkDICOMIndexer.cpp
@@ -148,56 +148,111 @@ void ctkDICOMIndexer::addDirectory(ctkDICOMDatabase& ctkDICOMDatabase,
 {
   Q_D(ctkDICOMIndexer);
 
-  // currently it is not supported to have multiple
-  // parallel directory imports so the second call blocks
-  //
-  d->DirectoryImportWatcher.waitForFinished();
+  QStringList listOfFiles;
+  QDir directory(directoryName);
 
-  const std::string src_directory(directoryName.toStdString());
-
-  OFList originalDcmtkFileNames;
-  OFList dcmtkFileNames;
-  OFStandard::searchDirectoryRecursively( QDir::toNativeSeparators(src_directory.c_str()).toAscii().data(), originalDcmtkFileNames, "", "");
-
-  int totalNumberOfFiles = originalDcmtkFileNames.size();
+  if(directory.exists("DICOMDIR"))
+  {
+    addDicomdir(ctkDICOMDatabase,directoryName,destinationDirectoryName);
+  }
+  else
+  {
+    QDirIterator it(directoryName,QDir::Files,QDirIterator::Subdirectories);
+    while(it.hasNext())
+    {
+      listOfFiles << it.next();
+    }
+    emit foundFilesToIndex(listOfFiles.count());
+    addListOfFiles(ctkDICOMDatabase,listOfFiles,destinationDirectoryName);
+  }
+}
 
-  // hack to reverse list of filenames (not neccessary when image loading works correctly)
-  for ( OFListIterator(OFString) iter = originalDcmtkFileNames.begin(); iter != originalDcmtkFileNames.end(); ++iter )
+//------------------------------------------------------------------------------
+void ctkDICOMIndexer::addListOfFiles(ctkDICOMDatabase& ctkDICOMDatabase,
+                                     const QStringList& listOfFiles,
+                                     const QString& destinationDirectoryName)
+{
+  Q_D(ctkDICOMIndexer);
+  if(!listOfFiles.isEmpty())
   {
-    dcmtkFileNames.push_front( *iter );
+    if(d->DirectoryImportWatcher.isRunning())
+    {
+      d->DirectoryImportWatcher.cancel();
+      d->DirectoryImportWatcher.waitForFinished();
+    }
+    d->FilesToIndex.append(listOfFiles);
+    d->DirectoryImportFuture = QtConcurrent::filter(d->FilesToIndex,AddFileFunctor(this,ctkDICOMDatabase,destinationDirectoryName));
+    d->DirectoryImportWatcher.setFuture(d->DirectoryImportFuture);
   }
+}
 
-  OFListIterator(OFString) iter = dcmtkFileNames.begin();
+//------------------------------------------------------------------------------
+void ctkDICOMIndexer::addDicomdir(ctkDICOMDatabase& ctkDICOMDatabase,
+                 const QString& directoryName,
+                 const QString& destinationDirectoryName
+                 )
+{
+  Q_D(ctkDICOMIndexer);
+
+  //Initialize dicomdir with directory path
+  QString dcmFilePath = directoryName;
+  dcmFilePath.append("/DICOMDIR");
+  DcmDicomDir* dicomDir = new DcmDicomDir(dcmFilePath.toStdString().c_str());
 
-  OFListIterator(OFString) last = dcmtkFileNames.end();
+  //Values to store records data at the moment only uid needed
+  OFString patientsName, studyInstanceUID, seriesInstanceUID, sopInstanceUID, referencedFileName ;
 
-  if(iter == last) return;
+  //Variables for progress operations
+  QString instanceFilePath;
+  QStringList listOfInstances;
 
-  emit foundFilesToIndex(totalNumberOfFiles);
+  DcmDirectoryRecord* rootRecord = &(dicomDir->getRootRecord());
+  DcmDirectoryRecord* patientRecord = NULL;
+  DcmDirectoryRecord* studyRecord = NULL;
+  DcmDirectoryRecord* seriesRecord = NULL;
+  DcmDirectoryRecord* fileRecord = NULL;
 
-  /* iterate over all input filenames */
-  int fileNumber = 0;
-  int currentProgress = -1;
-  d->Canceled = false;
-  while (iter != last)
+  /*Iterate over all records in dicomdir and setup path to the dataset of the filerecord
+  then insert. the filerecord into the database.
+  If any UID is missing the record and all of it's subelements won't be added to the database*/
+  if(rootRecord != NULL)
   {
-    if (d->Canceled)
+    while (((patientRecord = rootRecord->nextSub(patientRecord)) != NULL)
+      &&(patientRecord->findAndGetOFString(DCM_PatientName, patientsName).good()))
+    {
+      logger.debug( "Reading new Patients:" );
+      logger.debug( "Patient's Name: " + QString(patientsName.c_str()) );
+
+      while (((studyRecord = patientRecord->nextSub(studyRecord)) != NULL)
+        && (studyRecord->findAndGetOFString(DCM_StudyInstanceUID, studyInstanceUID).good()))
       {
-      break;
+        logger.debug( "Reading new Studys:" );
+        logger.debug( "Studies Name: " + QString(studyInstanceUID.c_str()) );
+
+        while (((seriesRecord = studyRecord->nextSub(seriesRecord)) != NULL)
+          &&(seriesRecord->findAndGetOFString(DCM_SeriesInstanceUID, seriesInstanceUID).good()))
+        {
+          logger.debug( "Reading new Series:" );
+          logger.debug( "Series Instance Name: " + QString(seriesInstanceUID.c_str()) );
+
+          while (((fileRecord = seriesRecord->nextSub(fileRecord)) != NULL)
+            &&(fileRecord->findAndGetOFStringArray(DCM_ReferencedSOPInstanceUIDInFile, sopInstanceUID).good())
+            &&(fileRecord->findAndGetOFStringArray(DCM_ReferencedFileID,referencedFileName).good()))
+          {
+
+            //Get the filepath of the instance and insert it into a list
+            instanceFilePath = directoryName;
+            instanceFilePath.append("/");
+            instanceFilePath.append(QString( referencedFileName.c_str() ));
+            instanceFilePath.replace("\\","/");
+            listOfInstances << instanceFilePath;
+          }
+        }
       }
-    emit indexingFileNumber(++fileNumber);
-    int newProgress = ( fileNumber * 100 ) / totalNumberOfFiles;
-    if (newProgress != currentProgress)
-    {
-      currentProgress = newProgress;
-      emit progress( currentProgress );
     }
-    QString filePath((*iter).c_str());
-    d->FilesToIndex << filePath;
-    ++iter;
+    emit foundFilesToIndex(listOfInstances.count());
+    addListOfFiles(ctkDICOMDatabase,listOfInstances,destinationDirectoryName);
   }
-  d->DirectoryImportFuture = QtConcurrent::filter(d->FilesToIndex,AddFileFunctor(this,ctkDICOMDatabase,destinationDirectoryName));
-  d->DirectoryImportWatcher.setFuture(d->DirectoryImportFuture);
 }
 
 //------------------------------------------------------------------------------
@@ -209,7 +264,6 @@ void ctkDICOMIndexer::refreshDatabase(ctkDICOMDatabase& dicomDatabase, const QSt
    * Probably this should go to the database class as well
    * Or we have to extend the interface to make possible what we do here
    * without using SQL directly
-   
 
   /// get all filenames from the database
   QSqlQuery allFilesQuery(dicomDatabase.database());
diff --git a/Libs/DICOM/Core/ctkDICOMIndexer.h b/Libs/DICOM/Core/ctkDICOMIndexer.h
index f1a41973fb..59306bec85 100644
--- a/Libs/DICOM/Core/ctkDICOMIndexer.h
+++ b/Libs/DICOM/Core/ctkDICOMIndexer.h
@@ -51,6 +51,25 @@ class CTK_DICOM_CORE_EXPORT ctkDICOMIndexer : public QObject
   Q_INVOKABLE void addDirectory(ctkDICOMDatabase& database, const QString& directoryName,
                     const QString& destinationDirectoryName = "");
 
+  ///
+  /// \brief Adds directory to database by using DICOMDIR and optionally copies files to
+  /// destinationDirectory.
+  /// Scan the directory using Dcmtk and populate the database with all the
+  /// DICOM images accordingly.
+  ///
+  Q_INVOKABLE void addDicomdir(ctkDICOMDatabase& database, const QString& directoryName,
+                    const QString& destinationDirectoryName = "");
+
+  ///
+  /// \brief Adds a QStringList containing the file path to database and optionally copies files to
+  /// destinationDirectory.
+  ///
+  /// Scan the directory using Dcmtk and populate the database with all the
+  /// DICOM images accordingly.
+  ///
+  Q_INVOKABLE void addListOfFiles(ctkDICOMDatabase& database, const QStringList& listOfFiles,
+                    const QString& destinationDirectoryName = "");
+
   ///
   /// \brief Adds a file to database and optionally copies the file to
   /// destinationDirectory.

From 1bba6779d316437aa9d51bce93e7ced2333cddff Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Thu, 9 Aug 2012 22:03:34 +0200
Subject: [PATCH 104/247] Set the Qt plugin install path if it is not properly
 overridden. Fixes #228

---
 CMake/ctkMacroBuildQtPlugin.cmake | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CMake/ctkMacroBuildQtPlugin.cmake b/CMake/ctkMacroBuildQtPlugin.cmake
index 254c3250dc..a8d61243a1 100644
--- a/CMake/ctkMacroBuildQtPlugin.cmake
+++ b/CMake/ctkMacroBuildQtPlugin.cmake
@@ -127,7 +127,7 @@ macro(ctkMacroBuildQtPlugin)
   # CTK_INSTALL_QTPLUGIN_DIR:STRING can be passed when configuring CTK
   # By default, it is the same path as CTK_INSTALL_LIB_DIR
   # Plugins are installed in a subdirectory corresponding to their types (e.g. designer, iconengines, imageformats...)
-  if (NOT DEFINED CTK_INSTALL_QTPLUGIN_DIR)
+  if (NOT CTK_INSTALL_QTPLUGIN_DIR)
     set(CTK_INSTALL_QTPLUGIN_DIR "${CTK_INSTALL_LIB_DIR}")
   endif()
   install(TARGETS ${lib_name}

From 479f9ab479a268424166c65a9e2d229179a71093 Mon Sep 17 00:00:00 2001
From: Caspar Goch 
Date: Mon, 13 Aug 2012 12:15:24 +0200
Subject: [PATCH 105/247] Debug and release libs are now stored separately

Changed the DCMTK script to install the debug and release libs as well as
the binaries to Debug/Release subfolders. Furthermore changed the
FindDCMTK scipt to search these folders and add only the libs
corresponding to the current build selection.

This was done to fix the inability to do a Microsoft Visual Studio 2010
Debug and Release superbuild.
---
 CMakeExternals/DCMTK.cmake      |   3 +
 Utilities/CMake/FindDCMTK.cmake | 471 ++++++++++----------------------
 2 files changed, 152 insertions(+), 322 deletions(-)

diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake
index 5b1d6ff17c..55dc9326c1 100644
--- a/CMakeExternals/DCMTK.cmake
+++ b/CMakeExternals/DCMTK.cmake
@@ -48,6 +48,9 @@ if(${add_project})
         CMAKE_GENERATOR ${gen}
         UPDATE_COMMAND ""
         BUILD_COMMAND ""
+        CMAKE_ARGS
+          -DDCMTK_INSTALL_BINDIR:STRING=bin/${CMAKE_CFG_INTDIR}
+          -DDCMTK_INSTALL_LIBDIR:STRING=lib/${CMAKE_CFG_INTDIR}
         CMAKE_CACHE_ARGS
           ${ep_common_cache_args}
           -DBUILD_SHARED_LIBS:BOOL=OFF
diff --git a/Utilities/CMake/FindDCMTK.cmake b/Utilities/CMake/FindDCMTK.cmake
index 9869ec03be..93548deca3 100644
--- a/Utilities/CMake/FindDCMTK.cmake
+++ b/Utilities/CMake/FindDCMTK.cmake
@@ -1,7 +1,9 @@
+# adapted version of FindDCMTK, better suited for super-builds
+
 # - find DCMTK libraries and applications
 #
 
-#  DCMTK_INCLUDE_DIR   - Directories to include to use DCMTK
+#  DCMTK_INCLUDE_DIRS   - Directories to include to use DCMTK
 #  DCMTK_LIBRARIES     - Files to link against to use DCMTK
 #  DCMTK_FOUND         - If false, don't try to use DCMTK
 #  DCMTK_DIR           - (optional) Source directory for DCMTK
@@ -13,7 +15,8 @@
 
 #=============================================================================
 # Copyright 2004-2009 Kitware, Inc.
-# Copyright 2009 Mathieu Malaterre 
+# Copyright 2009-2010 Mathieu Malaterre 
+# Copyright 2010 Thomas Sondergaard 
 #
 # Distributed under the OSI-approved BSD License (the "License");
 # see accompanying file Copyright.txt for details.
@@ -28,338 +31,162 @@
 #
 # Written for VXL by Amitha Perera.
 # Upgraded for GDCM by Mathieu Malaterre.
-# 
-
-if( NOT DCMTK_FOUND )
-  set( DCMTK_DIR "/usr/include/dcmtk/"
-    CACHE PATH "Root of DCMTK source tree (optional)." )
-  mark_as_advanced( DCMTK_DIR )
-endif()
-
-find_path( DCMTK_config_INCLUDE_DIR osconfig.h
-  PATHS
-    ${DCMTK_DIR}/config/include
-    ${DCMTK_DIR}/config
-    ${DCMTK_DIR}/include/dcmtk/config
-    ${DCMTK_DIR}/include
-  NO_DEFAULT_PATH
-  
-)
-
-find_path( DCMTK_ofstd_INCLUDE_DIR ofstdinc.h
-  PATHS
-    ${DCMTK_DIR}/ofstd/include
-    ${DCMTK_DIR}/ofstd
-    ${DCMTK_DIR}/include/ofstd
-    ${DCMTK_DIR}/include/dcmtk/ofstd
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_ofstd_LIBRARY ofstd
-  PATHS
-    ${DCMTK_DIR}/ofstd/libsrc
-    ${DCMTK_DIR}/ofstd/libsrc/Release
-    ${DCMTK_DIR}/ofstd/libsrc/Debug
-    ${DCMTK_DIR}/ofstd/Release
-    ${DCMTK_DIR}/ofstd/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_path( DCMTK_oflog_INCLUDE_DIR logger.h
-  PATHS
-    ${DCMTK_DIR}/oflog/include
-    ${DCMTK_DIR}/oflog
-    ${DCMTK_DIR}/include/oflog
-    ${DCMTK_DIR}/include/dcmtk/oflog
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_oflog_LIBRARY oflog
-  PATHS
-    ${DCMTK_DIR}/oflog/libsrc
-    ${DCMTK_DIR}/oflog/libsrc/Release
-    ${DCMTK_DIR}/oflog/libsrc/Debug
-    ${DCMTK_DIR}/oflog/Release
-    ${DCMTK_DIR}/oflog/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-
-
-find_path( DCMTK_dcmdata_INCLUDE_DIR dctypes.h
-  PATHS
-    ${DCMTK_DIR}/include/dcmdata
-    ${DCMTK_DIR}/include/dcmtk/dcmdata
-    ${DCMTK_DIR}/dcmdata
-    ${DCMTK_DIR}/dcmdata/include
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_dcmdata_LIBRARY dcmdata
-  PATHS
-    ${DCMTK_DIR}/dcmdata/libsrc
-    ${DCMTK_DIR}/dcmdata/libsrc/Release
-    ${DCMTK_DIR}/dcmdata/libsrc/Debug
-    ${DCMTK_DIR}/dcmdata/Release
-    ${DCMTK_DIR}/dcmdata/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_path( DCMTK_dcmjpeg_INCLUDE_DIR djdecode.h
-  PATHS
-    ${DCMTK_DIR}/include/dcmjpeg
-    ${DCMTK_DIR}/include/dcmtk/dcmjpeg
-    ${DCMTK_DIR}/dcmjpeg
-    ${DCMTK_DIR}/dcmjpeg/include
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_dcmjpeg_LIBRARY dcmjpeg
-  PATHS
-    ${DCMTK_DIR}/dcmjpeg/libsrc
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Release
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Debug
-    ${DCMTK_DIR}/dcmjpeg/Release
-    ${DCMTK_DIR}/dcmjpeg/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_ijg12_LIBRARY ijg12
-  PATHS
-    ${DCMTK_DIR}/dcmjpeg/libsrc
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Release
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Debug
-    ${DCMTK_DIR}/dcmjpeg/Release
-    ${DCMTK_DIR}/dcmjpeg/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_ijg16_LIBRARY ijg16
-  PATHS
-    ${DCMTK_DIR}/dcmjpeg/libsrc
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Release
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Debug
-    ${DCMTK_DIR}/dcmjpeg/Release
-    ${DCMTK_DIR}/dcmjpeg/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_ijg8_LIBRARY ijg8
-  PATHS
-    ${DCMTK_DIR}/dcmjpeg/libsrc
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Release
-    ${DCMTK_DIR}/dcmjpeg/libsrc/Debug
-    ${DCMTK_DIR}/dcmjpeg/Release
-    ${DCMTK_DIR}/dcmjpeg/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_path( DCMTK_dcmnet_INCLUDE_DIR dimse.h
-  PATHS
-    ${DCMTK_DIR}/include/dcmnet
-    ${DCMTK_DIR}/include/dcmtk/dcmnet
-    ${DCMTK_DIR}/dcmnet
-    ${DCMTK_DIR}/dcmnet/include
-  NO_DEFAULT_PATH
-)
-
-find_library( DCMTK_dcmnet_LIBRARY dcmnet
-  PATHS
-    ${DCMTK_DIR}/dcmnet/libsrc
-    ${DCMTK_DIR}/dcmnet/libsrc/Release
-    ${DCMTK_DIR}/dcmnet/libsrc/Debug
-    ${DCMTK_DIR}/dcmnet/Release
-    ${DCMTK_DIR}/dcmnet/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-find_path( DCMTK_dcmimgle_INCLUDE_DIR dcmimage.h
-  PATHS
-    ${DCMTK_DIR}/dcmimgle/include
-    ${DCMTK_DIR}/dcmimgle
-    ${DCMTK_DIR}/include/dcmimgle
-    ${DCMTK_DIR}/include/dcmtk/dcmimgle
-  NO_DEFAULT_PATH
-)
+# Modified for EasyViz by Thomas Sondergaard.
+#
 
-find_library( DCMTK_dcmimgle_LIBRARY dcmimgle
-  PATHS
-    ${DCMTK_DIR}/dcmimgle/libsrc
-    ${DCMTK_DIR}/dcmimgle/libsrc/Release
-    ${DCMTK_DIR}/dcmimgle/libsrc/Debug
-    ${DCMTK_DIR}/dcmimgle/Release
-    ${DCMTK_DIR}/dcmimgle/Debug
-    ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
+# prefer DCMTK_DIR over default system paths like /usr/lib
+set(CMAKE_PREFIX_PATH ${DCMTK_DIR}/lib ${CMAKE_PREFIX_PATH}) # this is given to FIND_LIBRARY or FIND_PATH
 
-find_path( DCMTK_dcmimage_INCLUDE_DIR diregist.h
-  PATHS
-    ${DCMTK_DIR}/dcmimage/include
-    ${DCMTK_DIR}/dcmimage
-    ${DCMTK_DIR}/include/dcmimage
-    ${DCMTK_DIR}/include/dcmtk/dcmimage
-  NO_DEFAULT_PATH
-)
+if(NOT DCMTK_FOUND AND NOT DCMTK_DIR)
+  set(DCMTK_DIR
+    "/usr/include/dcmtk/"
+    CACHE
+    PATH
+    "Root of DCMTK source tree (optional).")
+  mark_as_advanced(DCMTK_DIR)
+endif()
 
-find_library( DCMTK_dcmimage_LIBRARY dcmimage
-  PATHS
-    ${DCMTK_DIR}/dcmimage/libsrc
-    ${DCMTK_DIR}/dcmimage/libsrc/Release
-    ${DCMTK_DIR}/dcmimage/libsrc/Debug
-    ${DCMTK_DIR}/dcmimage/Release
-    ${DCMTK_DIR}/dcmimage/Debug
+foreach(lib
+    dcmdata
+    dcmimage
+    dcmimgle
+    dcmjpeg
+    dcmnet
+    dcmpstat
+    dcmqrdb
+    dcmsign
+    dcmsr
+    dcmtls
+    ijg12
+    ijg16
+    ijg8
+    oflog
+    ofstd)
+
+  message("** \n\n\n\n I am looking for ${lib} in the following paths")
+  message("** ${DCMTK_DIR}/${lib}/libsrc")
+  message("** ${DCMTK_DIR}/${lib}/libsrc/Release")
+  message("** ${DCMTK_DIR}/${lib}/Release")
+  message("** ${DCMTK_DIR}/lib")
+  message("** ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release")
+  message("** That be it \n\n\n\n\n")
+  # Find Release libraries
+  find_library(DCMTK_${lib}_LIBRARY
+    ${lib}
+    PATHS
+    ${DCMTK_DIR}/${lib}/libsrc
+    ${DCMTK_DIR}/${lib}/libsrc/Release
+    ${DCMTK_DIR}/${lib}/Release
     ${DCMTK_DIR}/lib
-  NO_DEFAULT_PATH
-)
-
-# MM: I could not find this library on debian system / dcmtk 3.5.4
-# Michael Onken: this module is now called dcmqrdb. I will re-work that script soon...
-find_library(DCMTK_imagedb_LIBRARY imagedb
-  PATHS
-    ${DCMTK_DIR}/imagectn/libsrc/Release
-    ${DCMTK_DIR}/imagectn/libsrc/
-    ${DCMTK_DIR}/imagectn/libsrc/Debug
-  NO_DEFAULT_PATH
-  )
+    ${DCMTK_DIR}/lib/Release
+    ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release
+    NO_DEFAULT_PATH
+    )
+    
+  mark_as_advanced(DCMTK_${lib}_LIBRARY)
 
-if( DCMTK_config_INCLUDE_DIR 
-    AND DCMTK_ofstd_INCLUDE_DIR 
-    AND DCMTK_ofstd_LIBRARY
-    AND DCMTK_oflog_INCLUDE_DIR    
-    AND DCMTK_oflog_LIBRARY
-    AND DCMTK_dcmdata_INCLUDE_DIR
-    AND DCMTK_dcmdata_LIBRARY
-    AND DCMTK_dcmjpeg_INCLUDE_DIR
-    AND DCMTK_dcmjpeg_LIBRARY
-    AND DCMTK_dcmnet_INCLUDE_DIR
-    AND DCMTK_dcmnet_LIBRARY    
-    AND DCMTK_dcmimgle_INCLUDE_DIR
-    AND DCMTK_dcmimgle_LIBRARY 
-    AND DCMTK_dcmimage_INCLUDE_DIR
-    AND DCMTK_dcmimage_LIBRARY)
+  message("** DCMTKs ${lib} found at ${DCMTK_${lib}_LIBRARY}")
 
-#   # Wrap library is required on Linux
-#   if(NOT WIN32)
-#     find_library(DCMTK_wrap_LIBRARY wrap)
-#     message(DCMTK_wrap_LIBRARY:${DCMTK_wrap_LIBRARY})
-#     if(NOT DCMTK_wrap_LIBRARY)
-#       message(FATAL_ERROR "error: Wrap library is required to use DCMTK. "
-#                           "On Ubuntu, you could install it using 'sudo apt-get libwrap0'")
-#     endif()
-#   endif()
-
-  set(CMAKE_THREAD_LIBS_INIT)
-  if(DCMTK_oflog_LIBRARY)
-    # Hack - Not having a DCMTKConfig.cmake file to read the settings from, we will attempt to 
-    # find the library in all cases.
-    # Ideally, pthread library should be discovered only if DCMTK_WITH_THREADS is enabled.
-    set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
-    find_package(Threads)
+  if(DCMTK_${lib}_LIBRARY)
+    list(APPEND DCMTK_LIBRARIES_RELEASE optimized ${DCMTK_${lib}_LIBRARY})
   endif()
   
-  set( DCMTK_FOUND "YES" )
-  set( DCMTK_INCLUDE_DIR
-    ${DCMTK_DIR}/include
-    ${DCMTK_config_INCLUDE_DIR}
-    ${DCMTK_ofstd_INCLUDE_DIR}
-    ${DCMTK_oflog_INCLUDE_DIR}    
-    ${DCMTK_dcmdata_INCLUDE_DIR}
-    ${DCMTK_dcmjpeg_INCLUDE_DIR}
-    ${DCMTK_dcmnet_INCLUDE_DIR}
-    ${DCMTK_dcmimgle_INCLUDE_DIR}
-    ${DCMTK_dcmimage_INCLUDE_DIR}
-  )
-
-  set( DCMTK_LIBRARIES
-    ${DCMTK_dcmimage_LIBRARY}
-    ${DCMTK_dcmimgle_LIBRARY}
-    ${DCMTK_dcmnet_LIBRARY}    
-    ${DCMTK_dcmjpeg_LIBRARY}
-    ${DCMTK_dcmdata_LIBRARY}
-    ${DCMTK_ijg8_LIBRARY}
-    ${DCMTK_ijg12_LIBRARY}
-    ${DCMTK_ijg16_LIBRARY}
-    ${DCMTK_oflog_LIBRARY}    
-    ${DCMTK_ofstd_LIBRARY}
-    ${DCMTK_config_LIBRARY}
-    ${CMAKE_THREAD_LIBS_INIT}
-  )
-
-  if(DCMTK_imagedb_LIBRARY)
-   set( DCMTK_LIBRARIES
-   ${DCMTK_LIBRARIES}
-   ${DCMTK_imagedb_LIBRARY}
-   )
+  # Find Debug libraries
+  find_library(DCMTK_${lib}_LIBRARY_DEBUG
+    ${lib}
+    PATHS
+    ${DCMTK_DIR}/${lib}/libsrc
+    ${DCMTK_DIR}/${lib}/libsrc/Debug
+    ${DCMTK_DIR}/${lib}/Debug
+    ${DCMTK_DIR}/lib
+    ${DCMTK_DIR}/lib/Debug
+    ${DCMTK_DIR}/dcmjpeg/lib${lib}/Debug
+    NO_DEFAULT_PATH
+    )
+    
+  message("** DCMTKs ${lib} in debug found at ${DCMTK_${lib}_LIBRARY_DEBUG}")
+    
+  mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG)
+
+  if(DCMTK_${lib}_LIBRARY_DEBUG)
+    list(APPEND DCMTK_LIBRARIES_DEBUG debug ${DCMTK_${lib}_LIBRARY_DEBUG})
   endif()
 
-  if( WIN32 )
-    set( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ws2_32 netapi32 wsock32)
+endforeach()
+
+#depending on build type set debug or release
+list(APPEND DCMTK_LIBRARIES ${DCMTK_LIBRARIES_RELEASE} ${DCMTK_LIBRARIES_DEBUG} )
+
+message("** Overall there be the following libraries \n ${DCMTK_LIBRARIES}")
+
+set(DCMTK_config_TEST_HEADER osconfig.h)
+set(DCMTK_dcmdata_TEST_HEADER dctypes.h)
+set(DCMTK_dcmimage_TEST_HEADER dicoimg.h)
+set(DCMTK_dcmimgle_TEST_HEADER dcmimage.h)
+set(DCMTK_dcmjpeg_TEST_HEADER djdecode.h)
+set(DCMTK_dcmnet_TEST_HEADER assoc.h)
+set(DCMTK_dcmpstat_TEST_HEADER dcmpstat.h)
+set(DCMTK_dcmqrdb_TEST_HEADER dcmqrdba.h)
+set(DCMTK_dcmsign_TEST_HEADER sicert.h)
+set(DCMTK_dcmsr_TEST_HEADER dsrtree.h)
+set(DCMTK_dcmtls_TEST_HEADER tlslayer.h)
+set(DCMTK_ofstd_TEST_HEADER ofstdinc.h)
+
+foreach(dir
+    config
+    dcmdata
+    dcmimage
+    dcmimgle
+    dcmjpeg
+    dcmnet
+    dcmpstat
+    dcmqrdb
+    dcmsign
+    dcmsr
+    dcmtls
+    ofstd)
+  find_path(DCMTK_${dir}_INCLUDE_DIR
+    ${DCMTK_${dir}_TEST_HEADER}
+    PATHS
+    ${DCMTK_DIR}/${dir}/include
+    ${DCMTK_DIR}/${dir}
+    ${DCMTK_DIR}/include/dcmtk/${dir}
+    ${DCMTK_DIR}/include/${dir})
+
+  mark_as_advanced(DCMTK_${dir}_INCLUDE_DIR)
+  message("** DCMTKs ${dir} found at ${DCMTK_${dir}_INCLUDE_DIR}")
+
+  if(DCMTK_${dir}_INCLUDE_DIR)
+    list(APPEND
+      DCMTK_INCLUDE_DIRS
+      ${DCMTK_${dir}_INCLUDE_DIR})
   endif()
-  
-#   IF (NOT WIN32)
-#     set( DCMTK_LIBRARIES ${DCMTK_LIBRARIES} ${DCMTK_wrap_LIBRARY} )
-#   endif()
-
-endif()
-
-find_program(DCMTK_DCMDUMP_EXECUTABLE dcmdump
-  PATHS
-    ${DCMTK_DIR}/bin
-  NO_DEFAULT_PATH
-  )
+endforeach()
 
-find_program(DCMTK_DCMDJPEG_EXECUTABLE dcmdjpeg
-  PATHS
-    ${DCMTK_DIR}/bin
-  NO_DEFAULT_PATH
-  )
+list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_DIR}/include)
 
-find_program(DCMTK_DCMDRLE_EXECUTABLE dcmdrle
-  PATHS
-    ${DCMTK_DIR}/bin
-  NO_DEFAULT_PATH
-  )
-
-find_program(DCMTK_DCMQRSCP_EXECUTABLE dcmqrscp
-  PATHS
-    ${DCMTK_DIR}/bin
-  NO_DEFAULT_PATH
-  )
-
-find_program(DCMTK_STORESCU_EXECUTABLE storescu
-  PATHS
-    ${DCMTK_DIR}/bin
-  NO_DEFAULT_PATH
-  )
+if(WIN32)
+  list(APPEND DCMTK_LIBRARIES netapi32 wsock32)
+endif()
 
-mark_as_advanced(
-  DCMTK_DCMDUMP_EXECUTABLE
-  DCMTK_DCMDJPEG_EXECUTABLE
-  DCMTK_DCMDRLE_EXECUTABLE
-  DCMTK_DCMQRSCP_EXECUTABLE
-  DCMTK_STORESCU_EXECUTABLE
-  DCMTK_config_INCLUDE_DIR
-  DCMTK_dcmdata_INCLUDE_DIR
-  DCMTK_dcmdata_LIBRARY
-  DCMTK_dcmnet_INCLUDE_DIR
-  DCMTK_dcmnet_LIBRARY
-  DCMTK_dcmimgle_INCLUDE_DIR
-  DCMTK_dcmimgle_LIBRARY
-  DCMTK_dcmimage_INCLUDE_DIR
-  DCMTK_dcmimage_LIBRARY  
-  DCMTK_imagedb_LIBRARY 
-  DCMTK_ofstd_INCLUDE_DIR
-  DCMTK_ofstd_LIBRARY
-  DCMTK_oflog_INCLUDE_DIR
-  DCMTK_oflog_LIBRARY
-  )
+if(DCMTK_ofstd_INCLUDE_DIR)
+  get_filename_component(DCMTK_dcmtk_INCLUDE_DIR
+    ${DCMTK_ofstd_INCLUDE_DIR}
+    PATH
+    CACHE)
+  list(APPEND DCMTK_INCLUDE_DIRS ${DCMTK_dcmtk_INCLUDE_DIR})
+  mark_as_advanced(DCMTK_dcmtk_INCLUDE_DIR)
+endif()
 
+#include(FindPackageHandleStandardArgs)
+#find_package_handle_standard_args(DCMTK DEFAULT_MSG
+#  DCMTK_config_INCLUDE_DIR
+#  DCMTK_ofstd_INCLUDE_DIR
+#  DCMTK_ofstd_LIBRARY
+#  DCMTK_dcmdata_INCLUDE_DIR
+#  DCMTK_dcmdata_LIBRARY
+#  DCMTK_dcmimgle_INCLUDE_DIR
+#  DCMTK_dcmimgle_LIBRARY)
+
+# Compatibility: This variable is deprecated
+set(DCMTK_INCLUDE_DIR ${DCMTK_INCLUDE_DIRS})

From d2c9d8f68744b580eb445e14840fa244bb23e2d1 Mon Sep 17 00:00:00 2001
From: Caspar Goch 
Date: Mon, 13 Aug 2012 12:48:40 +0200
Subject: [PATCH 106/247] Removed debug output

---
 Utilities/CMake/FindDCMTK.cmake | 25 ++-----------------------
 1 file changed, 2 insertions(+), 23 deletions(-)

diff --git a/Utilities/CMake/FindDCMTK.cmake b/Utilities/CMake/FindDCMTK.cmake
index 93548deca3..6584eda8f3 100644
--- a/Utilities/CMake/FindDCMTK.cmake
+++ b/Utilities/CMake/FindDCMTK.cmake
@@ -63,13 +63,6 @@ foreach(lib
     oflog
     ofstd)
 
-  message("** \n\n\n\n I am looking for ${lib} in the following paths")
-  message("** ${DCMTK_DIR}/${lib}/libsrc")
-  message("** ${DCMTK_DIR}/${lib}/libsrc/Release")
-  message("** ${DCMTK_DIR}/${lib}/Release")
-  message("** ${DCMTK_DIR}/lib")
-  message("** ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release")
-  message("** That be it \n\n\n\n\n")
   # Find Release libraries
   find_library(DCMTK_${lib}_LIBRARY
     ${lib}
@@ -85,7 +78,7 @@ foreach(lib
     
   mark_as_advanced(DCMTK_${lib}_LIBRARY)
 
-  message("** DCMTKs ${lib} found at ${DCMTK_${lib}_LIBRARY}")
+  #message("** DCMTKs ${lib} found at ${DCMTK_${lib}_LIBRARY}")
 
   if(DCMTK_${lib}_LIBRARY)
     list(APPEND DCMTK_LIBRARIES_RELEASE optimized ${DCMTK_${lib}_LIBRARY})
@@ -104,8 +97,6 @@ foreach(lib
     NO_DEFAULT_PATH
     )
     
-  message("** DCMTKs ${lib} in debug found at ${DCMTK_${lib}_LIBRARY_DEBUG}")
-    
   mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG)
 
   if(DCMTK_${lib}_LIBRARY_DEBUG)
@@ -117,8 +108,6 @@ endforeach()
 #depending on build type set debug or release
 list(APPEND DCMTK_LIBRARIES ${DCMTK_LIBRARIES_RELEASE} ${DCMTK_LIBRARIES_DEBUG} )
 
-message("** Overall there be the following libraries \n ${DCMTK_LIBRARIES}")
-
 set(DCMTK_config_TEST_HEADER osconfig.h)
 set(DCMTK_dcmdata_TEST_HEADER dctypes.h)
 set(DCMTK_dcmimage_TEST_HEADER dicoimg.h)
@@ -154,7 +143,7 @@ foreach(dir
     ${DCMTK_DIR}/include/${dir})
 
   mark_as_advanced(DCMTK_${dir}_INCLUDE_DIR)
-  message("** DCMTKs ${dir} found at ${DCMTK_${dir}_INCLUDE_DIR}")
+  #message("** DCMTKs ${dir} found at ${DCMTK_${dir}_INCLUDE_DIR}")
 
   if(DCMTK_${dir}_INCLUDE_DIR)
     list(APPEND
@@ -178,15 +167,5 @@ if(DCMTK_ofstd_INCLUDE_DIR)
   mark_as_advanced(DCMTK_dcmtk_INCLUDE_DIR)
 endif()
 
-#include(FindPackageHandleStandardArgs)
-#find_package_handle_standard_args(DCMTK DEFAULT_MSG
-#  DCMTK_config_INCLUDE_DIR
-#  DCMTK_ofstd_INCLUDE_DIR
-#  DCMTK_ofstd_LIBRARY
-#  DCMTK_dcmdata_INCLUDE_DIR
-#  DCMTK_dcmdata_LIBRARY
-#  DCMTK_dcmimgle_INCLUDE_DIR
-#  DCMTK_dcmimgle_LIBRARY)
-
 # Compatibility: This variable is deprecated
 set(DCMTK_INCLUDE_DIR ${DCMTK_INCLUDE_DIRS})

From 1e9d40f196c23dd2c19d4d896ede54cbccd24311 Mon Sep 17 00:00:00 2001
From: Caspar Goch 
Date: Mon, 13 Aug 2012 16:01:39 +0200
Subject: [PATCH 107/247] Separated finding libraries and including them based
 on build type

---
 Utilities/CMake/FindDCMTK.cmake | 44 ++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 14 deletions(-)

diff --git a/Utilities/CMake/FindDCMTK.cmake b/Utilities/CMake/FindDCMTK.cmake
index 6584eda8f3..e093977262 100644
--- a/Utilities/CMake/FindDCMTK.cmake
+++ b/Utilities/CMake/FindDCMTK.cmake
@@ -46,6 +46,7 @@ if(NOT DCMTK_FOUND AND NOT DCMTK_DIR)
   mark_as_advanced(DCMTK_DIR)
 endif()
 
+# Find all libraries, store debug and release separately
 foreach(lib
     dcmdata
     dcmimage
@@ -64,7 +65,7 @@ foreach(lib
     ofstd)
 
   # Find Release libraries
-  find_library(DCMTK_${lib}_LIBRARY
+  find_library(DCMTK_${lib}_LIBRARY_RELEASE
     ${lib}
     PATHS
     ${DCMTK_DIR}/${lib}/libsrc
@@ -75,15 +76,7 @@ foreach(lib
     ${DCMTK_DIR}/dcmjpeg/lib${lib}/Release
     NO_DEFAULT_PATH
     )
-    
-  mark_as_advanced(DCMTK_${lib}_LIBRARY)
-
-  #message("** DCMTKs ${lib} found at ${DCMTK_${lib}_LIBRARY}")
 
-  if(DCMTK_${lib}_LIBRARY)
-    list(APPEND DCMTK_LIBRARIES_RELEASE optimized ${DCMTK_${lib}_LIBRARY})
-  endif()
-  
   # Find Debug libraries
   find_library(DCMTK_${lib}_LIBRARY_DEBUG
     ${lib}
@@ -97,17 +90,40 @@ foreach(lib
     NO_DEFAULT_PATH
     )
     
+  mark_as_advanced(DCMTK_${lib}_LIBRARY_RELEASE)
   mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG)
 
+endforeach()
+
+# Add libraries to variable according to build type
+# this is done as a separate loop for transparencies sake
+foreach(lib
+    dcmdata
+    dcmimage
+    dcmimgle
+    dcmjpeg
+    dcmnet
+    dcmpstat
+    dcmqrdb
+    dcmsign
+    dcmsr
+    dcmtls
+    ijg12
+    ijg16
+    ijg8
+    oflog
+    ofstd)
+
+  if(DCMTK_${lib}_LIBRARY_RELEASE)
+    list(APPEND DCMTK_LIBRARIES optimized ${DCMTK_${lib}_LIBRARY_RELEASE})
+  endif()
+  
   if(DCMTK_${lib}_LIBRARY_DEBUG)
-    list(APPEND DCMTK_LIBRARIES_DEBUG debug ${DCMTK_${lib}_LIBRARY_DEBUG})
+    list(APPEND DCMTK_LIBRARIES debug ${DCMTK_${lib}_LIBRARY_DEBUG})
   endif()
-
+  
 endforeach()
 
-#depending on build type set debug or release
-list(APPEND DCMTK_LIBRARIES ${DCMTK_LIBRARIES_RELEASE} ${DCMTK_LIBRARIES_DEBUG} )
-
 set(DCMTK_config_TEST_HEADER osconfig.h)
 set(DCMTK_dcmdata_TEST_HEADER dctypes.h)
 set(DCMTK_dcmimage_TEST_HEADER dicoimg.h)

From 514b5d6e6a1fc52260aec1cb0bd2a903b2827a34 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Mon, 13 Aug 2012 16:36:27 +0100
Subject: [PATCH 108/247] Provide QUiLoader and ctkCmdLineModuleXslTransform
 via protected virtual getters

---
 .../QtGui/ctkCmdLineModuleQtGui.cpp           | 62 +++++++++++++++++--
 .../QtGui/ctkCmdLineModuleQtGui_p.h           | 11 +++-
 2 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
index 6cffd919e1..62dd45744f 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp
@@ -32,12 +32,54 @@
 
 #include 
 
+//-----------------------------------------------------------------------------
 ctkCmdLineModuleQtGui::ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef)
   : ctkCmdLineModule(moduleRef),
+    Loader(NULL),
+    Transform(NULL),
     WidgetTree(NULL)
 {
 }
 
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleQtGui::~ctkCmdLineModuleQtGui()
+{
+  if (Loader != NULL)
+  {
+    delete Loader;
+  }
+
+  if (Transform != NULL)
+  {
+    delete Transform;
+  }
+}
+
+
+//-----------------------------------------------------------------------------
+QUiLoader* ctkCmdLineModuleQtGui::uiLoader() const
+{
+  if (Loader == NULL)
+  {
+    Loader = new QUiLoader();
+  }
+  return Loader;
+}
+
+
+//-----------------------------------------------------------------------------
+ctkCmdLineModuleXslTransform* ctkCmdLineModuleQtGui::xslTransform() const
+{
+  if (Transform == NULL)
+  {
+    Transform = new ctkCmdLineModuleXslTransform();
+  }
+  return Transform;
+}
+
+
+//-----------------------------------------------------------------------------
 QObject* ctkCmdLineModuleQtGui::guiHandle() const
 {
   if (WidgetTree) return WidgetTree;
@@ -47,15 +89,19 @@ QObject* ctkCmdLineModuleQtGui::guiHandle() const
 
   QBuffer uiForm;
   uiForm.open(QIODevice::ReadWrite);
-  ctkCmdLineModuleXslTransform xslTransform(&input, &uiForm);
-  if (!xslTransform.transform())
+
+  ctkCmdLineModuleXslTransform* xslTransform = this->xslTransform();
+  xslTransform->setInput(&input);
+  xslTransform->setOutput(&uiForm);
+
+  if (!xslTransform->transform())
   {
     // maybe throw an exception
-    qCritical() << xslTransform.errorString();
+    qCritical() << xslTransform->errorString();
     return 0;
   }
 
-  QUiLoader uiLoader;
+  QUiLoader* uiLoader = this->uiLoader();
 #ifdef CMAKE_INTDIR
   QString appPath = QCoreApplication::applicationDirPath();
   if (appPath.endsWith(CMAKE_INTDIR))
@@ -63,10 +109,12 @@ QObject* ctkCmdLineModuleQtGui::guiHandle() const
     uiLoader.addPluginPath(appPath + "/../designer");
   }
 #endif
-  WidgetTree = uiLoader.load(&uiForm);
+  WidgetTree = uiLoader->load(&uiForm);
   return WidgetTree;
 }
 
+
+//-----------------------------------------------------------------------------
 QVariant ctkCmdLineModuleQtGui::value(const QString ¶meter) const
 {
   if (!WidgetTree) return QVariant();
@@ -82,6 +130,8 @@ QVariant ctkCmdLineModuleQtGui::value(const QString ¶meter) const
   return QVariant();
 }
 
+
+//-----------------------------------------------------------------------------
 void ctkCmdLineModuleQtGui::setValue(const QString ¶meter, const QVariant &value)
 {
   if (!WidgetTree) return;
@@ -97,6 +147,8 @@ void ctkCmdLineModuleQtGui::setValue(const QString ¶meter, const QVariant &v
   }
 }
 
+
+//-----------------------------------------------------------------------------
 QList ctkCmdLineModuleQtGui::parameterNames() const
 {
   if (!ParameterNames.empty()) return ParameterNames;
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
index 00f8794b93..5f970beba3 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h
@@ -23,8 +23,11 @@
 #define CTKCMDLINEMODULEQTGUI_H
 
 #include 
+#include 
+#include 
 
 class ctkCmdLineModuleReference;
+class ctkCmdLineModuleXslTransform;
 
 class ctkCmdLineModuleQtGui : public ctkCmdLineModule
 {
@@ -32,6 +35,7 @@ class ctkCmdLineModuleQtGui : public ctkCmdLineModule
 public:
 
   ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef);
+  virtual ~ctkCmdLineModuleQtGui();
 
   // ctkCmdLineModule overrides
 
@@ -42,8 +46,13 @@ class ctkCmdLineModuleQtGui : public ctkCmdLineModule
 
   virtual QList parameterNames() const;
 
-private:
+protected:
 
+  virtual QUiLoader* uiLoader() const;
+  virtual ctkCmdLineModuleXslTransform* xslTransform() const;
+
+  mutable QUiLoader* Loader;
+  mutable ctkCmdLineModuleXslTransform* Transform;
   mutable QWidget* WidgetTree;
 
   // Cache the list of parameter names

From 0199f7dbfb3866e6c6da0039034b4849d09fee59 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Tue, 14 Aug 2012 10:24:28 +0100
Subject: [PATCH 109/247] Separate xsl for file and image types

---
 .../Resources/ctkCmdLineModuleXmlToQtUi.xsl   | 36 +++++++++++++++++--
 .../Core/ctkCmdLineModuleXslTransform.cpp     |  1 +
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
index 6f644eae7a..0047811501 100644
--- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
+++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl
@@ -321,11 +321,11 @@
   
   
 
-  
+  
     
     
       
@@ -348,7 +348,37 @@
       
     
   
-  
+
+  
+
+  
+    
+    
+      
+        
+          
+            
+            
+            
+              ctkPathLineEdit::Files
+            
+          
+        
+        
+          
+            
+              Browse...
+            
+          
+        
+      
+    
+  
+
   
 
-  
+  
     
     
       
         
-          
-            
-            
-            
-              ctkPathLineEdit::Files
-            
-          
+          
+            
+              
+                
+                
+                
+                  ctkPathLineEdit::Files
+                
+              
+            
+            
+              
+                
+                
+                
+                  ctkPathLineEdit::Files
+                
+              
+            
+          
         
         
           
@@ -351,22 +364,35 @@
 
   
 
-  
+  
     
     
       
         
-          
-            
-            
-            
-              ctkPathLineEdit::Files
-            
-          
+          
+            
+              
+                
+                
+                
+                  ctkPathLineEdit::Files
+                
+              
+            
+            
+              
+                
+                
+                
+                  ctkPathLineEdit::Files
+                
+              
+            
+          
         
         
           
diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
index cbfa9c6dfd..2c5c74e11e 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp
@@ -119,8 +119,10 @@ ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIO
   this->bindVariable("floatingWidget", QVariant(QString("QDoubleSpinBox")));
   this->bindVariable("vectorWidget", QVariant(QString("QLineEdit")));
   this->bindVariable("enumWidget", QVariant(QString("QComboBox")));
-  this->bindVariable("imageWidget", QVariant(QString("ctkPathLineEdit")));
-  this->bindVariable("fileWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("imageInputWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("imageOutputWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("fileInputWidget", QVariant(QString("ctkPathLineEdit")));
+  this->bindVariable("fileOutputWidget", QVariant(QString("ctkPathLineEdit")));
   this->bindVariable("directoryWidget", QVariant(QString("ctkPathLineEdit")));
   this->bindVariable("pointWidget", QVariant(QString("ctkCoordinatesWidget")));
   this->bindVariable("unsupportedWidget", QVariant(QString("QLabel")));

From 738c48c3948615d99fef02bb9f6270d4de4663e2 Mon Sep 17 00:00:00 2001
From: Caspar Goch 
Date: Tue, 14 Aug 2012 14:55:08 +0200
Subject: [PATCH 112/247] Add pthread to Link libraries and merge loops

---
 Utilities/CMake/FindDCMTK.cmake | 32 ++++++++------------------------
 1 file changed, 8 insertions(+), 24 deletions(-)

diff --git a/Utilities/CMake/FindDCMTK.cmake b/Utilities/CMake/FindDCMTK.cmake
index 505da50b10..54eb331433 100644
--- a/Utilities/CMake/FindDCMTK.cmake
+++ b/Utilities/CMake/FindDCMTK.cmake
@@ -92,28 +92,8 @@ foreach(lib
     
   mark_as_advanced(DCMTK_${lib}_LIBRARY_RELEASE)
   mark_as_advanced(DCMTK_${lib}_LIBRARY_DEBUG)
-
-endforeach()
-
-# Add libraries to variable according to build type
-# this is done as a separate loop for transparencies sake
-foreach(lib
-    dcmdata
-    dcmimage
-    dcmimgle
-    dcmjpeg
-    dcmnet
-    dcmpstat
-    dcmqrdb
-    dcmsign
-    dcmsr
-    dcmtls
-    ijg12
-    ijg16
-    ijg8
-    oflog
-    ofstd)
-
+  
+  # Add libraries to variable according to build type
   if(DCMTK_${lib}_LIBRARY_RELEASE)
     list(APPEND DCMTK_LIBRARIES optimized ${DCMTK_${lib}_LIBRARY_RELEASE})
   endif()
@@ -121,11 +101,11 @@ foreach(lib
   if(DCMTK_${lib}_LIBRARY_DEBUG)
     list(APPEND DCMTK_LIBRARIES debug ${DCMTK_${lib}_LIBRARY_DEBUG})
   endif()
-  
+
 endforeach()
 
 set(CMAKE_THREAD_LIBS_INIT)
-if( DCMTK_oflog_LIBRARY_RELEASE OR DCMTK_oflog_LIBRARY_DEBUG )
+if(DCMTK_oflog_LIBRARY_RELEASE OR DCMTK_oflog_LIBRARY_DEBUG)
   # Hack - Not having a DCMTKConfig.cmake file to read the settings from, we will attempt to
   # find the library in all cases.
   # Ideally, pthread library should be discovered only if DCMTK_WITH_THREADS is enabled.
@@ -133,6 +113,10 @@ if( DCMTK_oflog_LIBRARY_RELEASE OR DCMTK_oflog_LIBRARY_DEBUG )
   find_package(Threads)
 endif()
 
+if(CMAKE_THREAD_LIBS_INIT)
+  list(APPEND DCMTK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+endif()
+
 set(DCMTK_config_TEST_HEADER osconfig.h)
 set(DCMTK_dcmdata_TEST_HEADER dctypes.h)
 set(DCMTK_dcmimage_TEST_HEADER dicoimg.h)

From 39e158e1b769bae5f850a7cddd2e1e437855c0e9 Mon Sep 17 00:00:00 2001
From: Caspar Goch 
Date: Tue, 14 Aug 2012 16:20:51 +0200
Subject: [PATCH 113/247] rearranged libraries according to dependency

---
 Utilities/CMake/FindDCMTK.cmake | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/Utilities/CMake/FindDCMTK.cmake b/Utilities/CMake/FindDCMTK.cmake
index 54eb331433..ea8eb1e05a 100644
--- a/Utilities/CMake/FindDCMTK.cmake
+++ b/Utilities/CMake/FindDCMTK.cmake
@@ -48,21 +48,22 @@ endif()
 
 # Find all libraries, store debug and release separately
 foreach(lib
-    dcmdata
-    dcmimage
-    dcmimgle
-    dcmjpeg
-    dcmnet
     dcmpstat
-    dcmqrdb
-    dcmsign
     dcmsr
+    dcmsign
     dcmtls
+    dcmqrdb
+    dcmnet
+    dcmjpeg
+    dcmimage
+    dcmimgle
+    dcmdata
+    oflog
+    ofstd
     ijg12
     ijg16
     ijg8
-    oflog
-    ofstd)
+    )
 
   # Find Release libraries
   find_library(DCMTK_${lib}_LIBRARY_RELEASE

From 7204ff768a102a4876df71bef5d79119d0b6d1eb Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Wed, 15 Aug 2012 11:29:57 +0100
Subject: [PATCH 114/247] Change ctkCmdLineModule to only write command line
 arg if a value has been specified

---
 .../Core/ctkCmdLineModule.cpp                 | 42 +++++++++++++------
 1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
index a8dbbe8f2d..68121a2fcb 100644
--- a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
+++ b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
@@ -97,12 +97,15 @@ QStringList ctkCmdLineModule::commandLineArguments() const
   QStringList cmdLineArgs;
   QHash indexedArgs;
 
-  QHash currentValues = values();
   ctkCmdLineModuleDescription description = moduleReference().description();
+
+  QHash currentValues = values();
   QHashIterator valuesIter(currentValues);
+
   while(valuesIter.hasNext())
   {
     valuesIter.next();
+
     ctkCmdLineModuleParameter parameter = description.parameter(valuesIter.key());
     if (parameter.index() > -1)
     {
@@ -119,12 +122,8 @@ QStringList ctkCmdLineModule::commandLineArguments() const
       {
         argFlag = QString("--") + d->normalizeFlag(parameter.longFlag());
       }
-      QStringList args;
-      if (parameter.multiple())
-      {
-        args = valuesIter.value().toString().split(',', QString::SkipEmptyParts);
-      }
-      else if (parameter.tag() == "boolean")
+
+      if (parameter.tag() == "boolean")
       {
         if (valuesIter.value().toBool())
         {
@@ -133,12 +132,31 @@ QStringList ctkCmdLineModule::commandLineArguments() const
       }
       else
       {
-        args.push_back(valuesIter.value().toString());
-      }
+        QStringList args;
+        if (parameter.multiple())
+        {
+          args = valuesIter.value().toString().split(',', QString::SkipEmptyParts);
+        }
+        else
+        {
+          QString arg = valuesIter.value().toString();
+          if (arg.isEmpty())
+          {
+            arg = parameter.defaultValue();
+          }
+          if (!arg.isEmpty())
+          {
+            args.push_back(valuesIter.value().toString());
+          }
+        }
 
-      foreach(QString arg, args)
-      {
-        cmdLineArgs << argFlag << arg;
+        if (args.length() > 0) // don't write the argFlag if there was no argument, and no default.
+        {
+          foreach(QString arg, args)
+          {
+            cmdLineArgs << argFlag << arg;
+          }
+        }
       }
     }
   }

From 2c95ce4884adbc3af1e5366074650cdf49dd96b9 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Wed, 15 Aug 2012 11:30:52 +0100
Subject: [PATCH 115/247] Change ctkCmdLineModuleObjectTreeWalker to expose
 QObject* currentObject()

---
 .../QtGui/ctkCmdLineModuleObjectTreeWalker.cpp               | 5 +++++
 .../QtGui/ctkCmdLineModuleObjectTreeWalker_p.h               | 1 +
 2 files changed, 6 insertions(+)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
index f79105bdf9..06cd4ce294 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
@@ -122,6 +122,11 @@ QString ctkCmdLineModuleObjectTreeWalker::longFlag() const
   return v.isValid() ? v.toString() : QString();
 }
 
+QObject* ctkCmdLineModuleObjectTreeWalker::currentObject() const
+{
+  return CurrentObject;
+}
+
 int ctkCmdLineModuleObjectTreeWalker::index() const
 {
   QVariant v = property("index");
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
index a396055f32..23d577494f 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
@@ -53,6 +53,7 @@ class ctkCmdLineModuleObjectTreeWalker
   QString name() const;
   QString label() const;
   QVariant value() const;
+  QObject* currentObject() const;
 
   void setValue(const QVariant& value);
 

From a9e18a9a5e58fb38ef512e3de69a411163ba4df0 Mon Sep 17 00:00:00 2001
From: MattClarkson 
Date: Mon, 20 Aug 2012 07:53:50 +0100
Subject: [PATCH 116/247] Removed currentObject method, as it exposes
 underlying widgets

---
 .../QtGui/ctkCmdLineModuleObjectTreeWalker.cpp              | 5 -----
 .../QtGui/ctkCmdLineModuleObjectTreeWalker_p.h              | 6 +++++-
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
index 06cd4ce294..f79105bdf9 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp
@@ -122,11 +122,6 @@ QString ctkCmdLineModuleObjectTreeWalker::longFlag() const
   return v.isValid() ? v.toString() : QString();
 }
 
-QObject* ctkCmdLineModuleObjectTreeWalker::currentObject() const
-{
-  return CurrentObject;
-}
-
 int ctkCmdLineModuleObjectTreeWalker::index() const
 {
   QVariant v = property("index");
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
index 23d577494f..a562a889b5 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
+++ b/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h
@@ -27,6 +27,11 @@
 class QObject;
 class QVariant;
 
+/**
+ * \class ctkCmdLineModuleObjectTreeWalker
+ *
+ * Note: Deliberately not exported.
+ */
 class ctkCmdLineModuleObjectTreeWalker
 {
 
@@ -53,7 +58,6 @@ class ctkCmdLineModuleObjectTreeWalker
   QString name() const;
   QString label() const;
   QVariant value() const;
-  QObject* currentObject() const;
 
   void setValue(const QVariant& value);
 

From 9340a14d0cfc0008de000188bf7f9ca285aec494 Mon Sep 17 00:00:00 2001
From: Sascha Zelzer 
Date: Mon, 20 Aug 2012 17:12:24 +0200
Subject: [PATCH 117/247] Refactored code into front- and backends + many
 explorer app improvements.

---
 .../CMakeLists.txt                            |  18 +-
 .../ctkCLModuleExplorerMainWindow.cpp         | 122 ---------
 .../ctkCLModuleExplorerMainWindow.ui          |  98 -------
 ...CmdLineModuleExplorerDirectorySettings.cpp |  33 +++
 ...tkCmdLineModuleExplorerDirectorySettings.h |  17 +-
 .../ctkCmdLineModuleExplorerMainWindow.cpp    | 221 ++++++++++++++++
 ...h => ctkCmdLineModuleExplorerMainWindow.h} |  42 ++-
 .../ctkCmdLineModuleExplorerMainWindow.ui     | 240 ++++++++++++++++++
 ...ctkCmdLineModuleExplorerProgressWidget.cpp | 127 +++++++++
 .../ctkCmdLineModuleExplorerProgressWidget.h  |  70 +++++
 .../ctkCmdLineModuleExplorerProgressWidget.ui |  79 ++++++
 .../ctkCmdLineModuleExplorerTabList.cpp       | 116 +++++++++
 .../ctkCmdLineModuleExplorerTabList.h         |  60 +++++
 .../ctkCmdLineModuleExplorerTreeWidget.cpp    | 154 +++++++++++
 .../ctkCmdLineModuleExplorerTreeWidget.h      |  67 +++++
 .../ctkCommandLineModuleExplorerMain.cpp      |   2 +-
 ...lorer.qrc => ctkCmdLineModuleExplorer.qrc} |   1 +
 .../resources/pause.png                       | Bin 0 -> 865 bytes
 .../target_libraries.cmake                    |   4 +-
 CMakeLists.txt                                |  15 +-
 .../Backend/LocalProcess/CMakeLists.txt       |  63 +++++
 .../ctkCmdLineModuleBackendLocalProcess.cpp   | 154 +++++++++++
 .../ctkCmdLineModuleBackendLocalProcess.h     |  56 ++++
 .../ctkCmdLineModuleProcessTask.cpp           |   0
 .../ctkCmdLineModuleProcessTask.h             |   0
 .../LocalProcess/target_libraries.cmake       |   9 +
 Libs/CommandLineModules/Core/CMakeLists.txt   |   9 +-
 .../Core/Resources/ctkCmdLineModules.qrc      |   2 -
 .../Core/Testing/CMakeLists.txt               |   1 -
 .../Core/Testing/Cpp/CMakeLists.txt           |   9 -
 .../Core/ctkCmdLineModule.cpp                 | 203 ---------------
 ...actory.cpp => ctkCmdLineModuleBackend.cpp} |  16 +-
 .../Core/ctkCmdLineModuleBackend.h            |  55 ++++
 .../Core/ctkCmdLineModuleDirectoryWatcher.cpp |  23 +-
 .../Core/ctkCmdLineModuleFrontend.cpp         | 119 +++++++++
 ...ineModule.h => ctkCmdLineModuleFrontend.h} |  49 ++--
 .../ctkCmdLineModuleFrontendFactory.cpp}      |   8 +-
 ...ry.h => ctkCmdLineModuleFrontendFactory.h} |  29 ++-
 .../Core/ctkCmdLineModuleManager.cpp          | 117 +++++----
 .../Core/ctkCmdLineModuleManager.h            |  18 +-
 .../Core/ctkCmdLineModuleReference.cpp        |  18 +-
 .../Core/ctkCmdLineModuleReference.h          |   7 +-
 .../Core/ctkCmdLineModuleReference_p.h        |  10 +-
 .../Core/ctkCmdLineModuleRunException.cpp     |  41 +--
 .../Core/ctkCmdLineModuleRunException.h       |  40 +--
 .../ctkCmdLineModuleXmlProgressWatcher.cpp    |  27 +-
 .../Core/ctkCmdLineModuleXmlProgressWatcher.h |  27 +-
 .../Core/ctkCmdLineModuleXslTransform.cpp     |  16 +-
 .../Core/ctkCmdLineModuleXslTransform.h       |  11 +-
 .../{ => Frontend}/QtGui/CMakeLists.txt       |  11 +-
 .../QtGui}/Resources/QtDesigner.xsd           |   0
 .../Resources/ctkCmdLineModuleXmlToQtUi.xsl   |   0
 .../ctkCmdLineModulesFrontendQtGui.qrc        |   6 +
 .../Frontend/QtGui/Testing/CMakeLists.txt     |   2 +
 .../Frontend/QtGui/Testing/Cpp/CMakeLists.txt |  43 ++++
 .../ctkCmdLineModuleQtXslTransformTest.cpp}   |  40 ++-
 .../ctkCmdLineModuleFrontendFactoryQtGui.cpp  |  40 +++
 .../ctkCmdLineModuleFrontendFactoryQtGui.h    |  41 +++
 .../QtGui/ctkCmdLineModuleFrontendQtGui.cpp}  |  50 ++--
 .../QtGui/ctkCmdLineModuleFrontendQtGui.h}    |  30 +--
 .../ctkCmdLineModuleMenuFactoryQtGui.cpp      |   0
 .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h  |   2 +-
 .../ctkCmdLineModuleObjectTreeWalker.cpp      |   0
 .../ctkCmdLineModuleObjectTreeWalker_p.h      |   0
 .../QtGui/target_libraries.cmake              |   0
 .../CommandLineModules/Testing/CMakeLists.txt |   5 +
 .../Testing/Cpp/CMakeLists.txt                |  56 ++++
 .../Cpp/ctkCmdLineModuleFutureTest.cpp        |  96 ++++---
 .../Cpp/ctkCmdLineModuleSignalTester.cpp      | 116 +++++++++
 .../Cpp/ctkCmdLineModuleSignalTester.h        |  59 +++++
 .../Modules/Blur2dImage/CMakeLists.txt        |   0
 .../ctkCmdLineModuleBlur2dImage.cpp           |   0
 .../ctkCmdLineModuleBlur2dImage.qrc           |   0
 .../ctkCmdLineModuleBlur2dImage.xml           |   0
 .../{Core => }/Testing/Modules/CMakeLists.txt |   0
 .../Testing/Modules/TestBed/CMakeLists.txt    |   0
 .../TestBed/ctkCmdLineModuleTestBed.cpp       |   0
 .../TestBed/ctkCmdLineModuleTestBed.qrc       |   0
 .../TestBed/ctkCmdLineModuleTestBed.xml       |   0
 .../Testing/Modules/Tour/CMakeLists.txt       |   0
 .../Modules/Tour/ctkCmdLineModuleTour.cpp     |   0
 .../Modules/Tour/ctkCmdLineModuleTour.qrc     |   0
 .../Modules/Tour/ctkCmdLineModuleTour.xml     |   0
 83 files changed, 2476 insertions(+), 744 deletions(-)
 delete mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
 delete mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.ui
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp
 rename Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h => Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h (69%)
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp
 rename Applications/ctkCommandLineModuleExplorer/{ctkCLModuleExplorerMainWindow.h => ctkCmdLineModuleExplorerMainWindow.h} (57%)
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.cpp
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.ui
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp
 create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h
 rename Applications/ctkCommandLineModuleExplorer/resources/{ctkCLModuleExplorer.qrc => ctkCmdLineModuleExplorer.qrc} (79%)
 create mode 100644 Applications/ctkCommandLineModuleExplorer/resources/pause.png
 create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt
 create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp
 create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h
 rename Libs/CommandLineModules/{Core => Backend/LocalProcess}/ctkCmdLineModuleProcessTask.cpp (100%)
 rename Libs/CommandLineModules/{Core => Backend/LocalProcess}/ctkCmdLineModuleProcessTask.h (100%)
 create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/target_libraries.cmake
 delete mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModule.cpp
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleFactory.cpp => ctkCmdLineModuleBackend.cpp} (88%)
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h
 create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp
 rename Libs/CommandLineModules/Core/{ctkCmdLineModule.h => ctkCmdLineModuleFrontend.h} (73%)
 rename Libs/CommandLineModules/{QtGui/ctkCmdLineModuleFactoryQtGui.cpp => Core/ctkCmdLineModuleFrontendFactory.cpp} (78%)
 rename Libs/CommandLineModules/Core/{ctkCmdLineModuleFactory.h => ctkCmdLineModuleFrontendFactory.h} (67%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/CMakeLists.txt (86%)
 rename Libs/CommandLineModules/{Core => Frontend/QtGui}/Resources/QtDesigner.xsd (100%)
 rename Libs/CommandLineModules/{Core => Frontend/QtGui}/Resources/ctkCmdLineModuleXmlToQtUi.xsl (100%)
 create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModulesFrontendQtGui.qrc
 create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Testing/CMakeLists.txt
 create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt
 rename Libs/CommandLineModules/{Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp => Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp} (91%)
 create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp
 create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h
 rename Libs/CommandLineModules/{QtGui/ctkCmdLineModuleQtGui.cpp => Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp} (68%)
 rename Libs/CommandLineModules/{QtGui/ctkCmdLineModuleQtGui_p.h => Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h} (74%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp (100%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h (96%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp (100%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h (100%)
 rename Libs/CommandLineModules/{ => Frontend}/QtGui/target_libraries.cmake (100%)
 create mode 100644 Libs/CommandLineModules/Testing/CMakeLists.txt
 create mode 100644 Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt
 rename Libs/CommandLineModules/{Core => }/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp (71%)
 create mode 100644 Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp
 create mode 100644 Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Blur2dImage/CMakeLists.txt (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/CMakeLists.txt (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/TestBed/CMakeLists.txt (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Tour/CMakeLists.txt (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc (100%)
 rename Libs/CommandLineModules/{Core => }/Testing/Modules/Tour/ctkCmdLineModuleTour.xml (100%)

diff --git a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt
index b8d9a42640..0da7d6cfa6 100644
--- a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt
+++ b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt
@@ -6,23 +6,31 @@ project(ctkCommandLineModuleExplorer)
 
 set(KIT_SRCS
   ctkCommandLineModuleExplorerMain.cpp
-  ctkCLModuleExplorerMainWindow.h
-  ctkCLModuleExplorerMainWindow.cpp
+  ctkCmdLineModuleExplorerDirectorySettings.cpp
+  ctkCmdLineModuleExplorerMainWindow.h
+  ctkCmdLineModuleExplorerMainWindow.cpp
+  ctkCmdLineModuleExplorerProgressWidget.cpp
+  ctkCmdLineModuleExplorerTabList.cpp
+  ctkCmdLineModuleExplorerTreeWidget.cpp
 )
 
 # Headers that should run through moc
 set(KIT_MOC_SRCS
-  ctkCLModuleExplorerMainWindow.h
+  ctkCmdLineModuleExplorerMainWindow.h
+  ctkCmdLineModuleExplorerProgressWidget.h
+  ctkCmdLineModuleExplorerTabList.h
+  ctkCmdLineModuleExplorerTreeWidget.h
 )
 
 # UI files
 set(KIT_UI_FORMS
-  ctkCLModuleExplorerMainWindow.ui
+  ctkCmdLineModuleExplorerMainWindow.ui
+  ctkCmdLineModuleExplorerProgressWidget.ui
 )
 
 # Resources
 set(KIT_resources
-  resources/ctkCLModuleExplorer.qrc
+  resources/ctkCmdLineModuleExplorer.qrc
 )
 
 set(QT_USE_QTUITOOLS 1)
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
deleted file mode 100644
index 55f65f24c9..0000000000
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*=============================================================================
-  
-  Library: CTK
-  
-  Copyright (c) German Cancer Research Center,
-    Division of Medical and Biological Informatics
-    
-  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
-    
-  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.
-  
-=============================================================================*/
-
-#include "ctkCLModuleExplorerMainWindow.h"
-#include "ui_ctkCLModuleExplorerMainWindow.h"
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
-  QMainWindow(parent),
-  ui(new Ui::ctkCLModuleExplorerMainWindow),
-  moduleManager(new ctkCmdLineModuleFactoryQtGui()),
-  watcher(NULL)
-{
-  ui->setupUi(this);
-}
-
-ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow()
-{
-  delete ui;
-}
-
-void ctkCLModuleExplorerMainWindow::addModuleTab(const ctkCmdLineModuleReference& moduleRef)
-{
-  ctkCmdLineModule* module = moduleManager.createModule(moduleRef);
-  if (!module) return;
-
-  QObject* guiHandle = module->guiHandle();
-
-  QWidget* widget = qobject_cast(guiHandle);
-  int tabIndex = ui->mainTabWidget->addTab(widget, widget->objectName());
-  mapTabToModuleRef[tabIndex] = module;
-}
-
-void ctkCLModuleExplorerMainWindow::addModule(const QString &location)
-{
-  ctkCmdLineModuleReference ref = moduleManager.registerModule(location);
-  if (ref)
-  {
-    addModuleTab(ref);
-  }
-}
-
-void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
-{
-  ctkCmdLineModule* module = mapTabToModuleRef[ui->mainTabWidget->currentIndex()];
-  if (!module)
-  {
-    qWarning() << "Invalid module instance";
-    return;
-  }
-
-  QStringList cmdLineArgs = module->commandLineArguments();
-  qDebug() << cmdLineArgs;
-
-  if (watcher != NULL)
-  {
-    delete watcher;
-  }
-  watcher = new QFutureWatcher();
-  QObject::connect(watcher, SIGNAL(started()), this, SLOT(moduleStarted()));
-  QObject::connect(watcher, SIGNAL(finished()), this, SLOT(moduleFinished()));
-  QObject::connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(moduleProgressValueChanged(int)));
-  QObject::connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(moduleProgressTextChanged(QString)));
-
-  ctkCmdLineModuleFuture future = module->run();
-  watcher->setFuture(future);
-
-//  try
-//  {
-//    future.waitForFinished();
-//  }
-//  catch (const ctkException& e)
-//  {
-//    qDebug() << e.printStackTrace();
-//  }
-}
-
-void ctkCLModuleExplorerMainWindow::moduleStarted()
-{
-  qDebug() << "*** moduleStarted";
-}
-
-void ctkCLModuleExplorerMainWindow::moduleFinished()
-{
-  qDebug() << "*** moduleFinished";
-}
-
-void ctkCLModuleExplorerMainWindow::moduleProgressValueChanged(int value)
-{
-  qDebug() << "*** moduleProgressValueChanged int=" << value;
-}
-
-void ctkCLModuleExplorerMainWindow::moduleProgressTextChanged(QString value)
-{
-  qDebug() << "*** moduleProgressTextChanged QString=" << value;
-}
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.ui b/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.ui
deleted file mode 100644
index 711c9146f8..0000000000
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.ui
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
- ctkCLModuleExplorerMainWindow
- 
-  
-   
-    0
-    0
-    800
-    600
-   
-  
-  
-   CTK Command Line Module Explorer
-  
-  
-   
-    
-     0
-    
-    
-     
-      
-       -1
-      
-      
-       Qt::ElideMiddle
-      
-      
-       true
-      
-      
-       true
-      
-     
-    
-   
-  
-  
-   
-    
-     0
-     0
-     800
-     25
-    
-   
-  
-  
-  
-   
-    toolBar
-   
-   
-    TopToolBarArea
-   
-   
-    false
-   
-   
-   
-  
-  
-   
-    
-     :/icons/run.png:/icons/run.png
-   
-   
-    Run
-   
-   
-    Run CLI Plug-in
-   
-   
-    Ctrl+R
-   
-  
-  
-   
-    
-     :/icons/stop.png:/icons/stop.png
-   
-   
-    Stop
-   
-   
-    Stop CLI Plug-in
-   
-   
-    Ctrl+C
-   
-  
- 
- 
-  
- 
- 
-
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp
new file mode 100644
index 0000000000..e4ebc77ea0
--- /dev/null
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp
@@ -0,0 +1,33 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  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
+    
+  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.
+  
+=============================================================================*/
+
+#include "ctkCmdLineModuleExplorerDirectorySettings.h"
+
+#include 
+
+#include 
+
+ctkCmdLineModuleExplorerDirectorySettings::ctkCmdLineModuleExplorerDirectorySettings()
+{
+  this->setWindowTitle("Module Paths");
+  this->setLayout(new QVBoxLayout());
+  this->layout()->addWidget(new ctkDirectoryListWidget());
+}
diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h
similarity index 69%
rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h
rename to Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h
index 4293b46a6f..2e513fea4f 100644
--- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.h
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h
@@ -19,20 +19,15 @@
   
 =============================================================================*/
 
-#ifndef CTKCMDLINEMODULEFACTORYQTGUI_H
-#define CTKCMDLINEMODULEFACTORYQTGUI_H
+#ifndef CTKCMDLINEMODULEEXPLORERDIRECTORYSETTINGS_H
+#define CTKCMDLINEMODULEEXPLORERDIRECTORYSETTINGS_H
 
-#include "ctkCmdLineModuleFactory.h"
+#include 
 
-#include "ctkCommandLineModulesQtGuiExport.h"
-
-class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFactoryQtGui
-    : public ctkCmdLineModuleFactory
+class ctkCmdLineModuleExplorerDirectorySettings : public ctkSettingsPanel
 {
 public:
-
-  ctkCmdLineModule* create(const ctkCmdLineModuleReference& moduleRef);
-
+  ctkCmdLineModuleExplorerDirectorySettings();
 };
 
-#endif // CTKCMDLINEMODULEFACTORYQTGUI_H
+#endif // CTKCMDLINEMODULEEXPLORERDIRECTORYSETTINGS_H
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp
new file mode 100644
index 0000000000..623e72e45a
--- /dev/null
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp
@@ -0,0 +1,221 @@
+/*=============================================================================
+  
+  Library: CTK
+  
+  Copyright (c) German Cancer Research Center,
+    Division of Medical and Biological Informatics
+    
+  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
+    
+  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.
+  
+=============================================================================*/
+
+#include "ctkCmdLineModuleExplorerMainWindow.h"
+#include "ui_ctkCmdLineModuleExplorerMainWindow.h"
+
+#include "ctkCmdLineModuleExplorerDirectorySettings.h"
+#include "ctkCmdLineModuleExplorerTabList.h"
+#include "ctkCmdLineModuleExplorerProgressWidget.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+
+ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) :
+  QMainWindow(parent),
+  ui(new Ui::ctkCmdLineModuleExplorerMainWindow),
+  tabList(NULL),
+  defaultModuleFrontendFactory(NULL),
+  directoryWatcher(&moduleManager)
+{
+  ui->setupUi(this);
+
+  // Frontends
+  moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtGui;
+  defaultModuleFrontendFactory = moduleFrontendFactories.front();
+
+  ui->modulesTreeWidget->setModuleFrontendFactories(moduleFrontendFactories);
+
+  // Backends
+  moduleBackends.push_back(new ctkCmdLineModuleBackendLocalProcess);
+  for(int i = 0; i < moduleBackends.size(); ++i)
+  {
+    moduleManager.registerBackend(moduleBackends[i]);
+  }
+
+  settingsDialog = new ctkSettingsDialog(this);
+  settingsDialog->addPanel(new ctkCmdLineModuleExplorerDirectorySettings());
+
+  tabList.reset(new ctkCmdLineModuleExplorerTabList(ui->mainTabWidget));
+
+  // If a module is registered via the ModuleManager, add it the tree
+  connect(&moduleManager, SIGNAL(moduleRegistered(ctkCmdLineModuleReference)), ui->modulesTreeWidget, SLOT(addModuleItem(ctkCmdLineModuleReference)));
+  // Double-clicking on an item in the tree creates a new tab with the default frontend
+  connect(ui->modulesTreeWidget, SIGNAL(moduleDoubleClicked(ctkCmdLineModuleReference)), this, SLOT(addModuleTab(ctkCmdLineModuleReference)));
+  // React to specific frontend creations
+  connect(ui->modulesTreeWidget, SIGNAL(moduleFrontendCreated(ctkCmdLineModuleFrontend*)), tabList.data(), SLOT(addTab(ctkCmdLineModuleFrontend*)));
+  // React to tab-changes
+  connect(tabList.data(), SIGNAL(tabActivated(ctkCmdLineModuleFrontend*)), SLOT(moduleTabActivated(ctkCmdLineModuleFrontend*)));
+
+  // Listen to future events for the currently active tab
+
+  // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is
+  // not emitted directly when the QFuture is paused. Instead, it is emitted after
+  // resuming the future, after the "resume" signal has been emitted... we use
+  // a polling aproach instead.
+  pollPauseTimer.setInterval(300);
+  connect(&pollPauseTimer, SIGNAL(timeout()), SLOT(checkModulePaused()));
+  connect(¤tFutureWatcher, SIGNAL(resumed()), SLOT(currentModuleResumed()));
+  connect(¤tFutureWatcher, SIGNAL(canceled()), SLOT(currentModuleCanceled()));
+  connect(¤tFutureWatcher, SIGNAL(finished()), SLOT(currentModuleFinished()));
+
+  directoryWatcher.setDebug(true);
+  directoryWatcher.setDirectories(QStringList(QCoreApplication::applicationDirPath()));
+
+  moduleTabActivated(NULL);
+
+  pollPauseTimer.start();
+}
+
+ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow()
+{
+  qDeleteAll(moduleBackends);
+  qDeleteAll(moduleFrontendFactories);
+}
+
+void ctkCLModuleExplorerMainWindow::addModule(const QUrl &location)
+{
+  moduleManager.registerModule(location);
+}
+
+void ctkCLModuleExplorerMainWindow::on_actionRun_triggered()
+{
+  ctkCmdLineModuleFrontend* moduleFrontend = this->tabList->activeTab();
+  Q_ASSERT(moduleFrontend);
+
+  ctkCmdLineModuleExplorerProgressWidget* progressWidget = new ctkCmdLineModuleExplorerProgressWidget();
+  this->ui->progressInfoWidget->layout()->addWidget(progressWidget);
+
+  ui->actionRun->setEnabled(false);
+  qobject_cast(moduleFrontend->guiHandle())->setEnabled(false);
+
+  ctkCmdLineModuleFuture future = moduleManager.run(moduleFrontend);
+
+  ui->actionPause->setEnabled(future.canPause() && future.isRunning());
+  ui->actionPause->setChecked(future.isPaused());
+  ui->actionCancel->setEnabled(future.canCancel() && future.isRunning());
+
+  progressWidget->setFuture(future);
+  this->currentFutureWatcher.setFuture(future);
+}
+
+void ctkCLModuleExplorerMainWindow::on_actionPause_toggled(bool toggled)
+{
+  this->currentFutureWatcher.setPaused(toggled);
+}
+
+void ctkCLModuleExplorerMainWindow::on_actionCancel_triggered()
+{
+  this->currentFutureWatcher.cancel();
+}
+
+void ctkCLModuleExplorerMainWindow::on_actionOptions_triggered()
+{
+  settingsDialog->exec();
+}
+
+void ctkCLModuleExplorerMainWindow::checkModulePaused()
+{
+  if (this->currentFutureWatcher.future().isPaused())
+  {
+    if (!ui->actionPause->isChecked())
+    {
+      ui->actionPause->setChecked(true);
+    }
+  }
+  else
+  {
+    if (ui->actionPause->isChecked())
+    {
+      ui->actionPause->setChecked(false);
+    }
+  }
+}
+
+void ctkCLModuleExplorerMainWindow::currentModuleResumed()
+{
+  ui->actionPause->setChecked(false);
+}
+
+void ctkCLModuleExplorerMainWindow::currentModuleCanceled()
+{
+  ctkCmdLineModuleFrontend* frontend = this->tabList->activeTab();
+  if (frontend)
+  {
+    ui->actionCancel->setEnabled(false);
+    ui->actionPause->setEnabled(false);
+    ui->actionRun->setEnabled(true);
+    QWidget* widget = qobject_cast(frontend->guiHandle());
+    if (widget)
+    {
+      widget->setEnabled(true);
+    }
+  }
+}
+
+void ctkCLModuleExplorerMainWindow::currentModuleFinished()
+{
+  ctkCmdLineModuleFrontend* frontend = this->tabList->activeTab();
+  if (frontend)
+  {
+    ui->actionCancel->setEnabled(false);
+    ui->actionPause->setEnabled(false);
+    ui->actionRun->setEnabled(true);
+    QWidget* widget = qobject_cast(frontend->guiHandle());
+    if (widget)
+    {
+      widget->setEnabled(true);
+    }
+  }
+}
+
+void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend *module)
+{
+  if (module == NULL)
+  {
+    ui->actionRun->setEnabled(false);
+    ui->actionPause->setEnabled(false);
+    ui->actionCancel->setEnabled(false);
+    currentFutureWatcher.setFuture(ctkCmdLineModuleFuture());
+  }
+  else
+  {
+    ui->actionRun->setEnabled(!module->isRunning());
+    ui->actionPause->setEnabled(module->future().canPause() && module->isRunning());
+    ui->actionPause->setChecked(module->isPaused());
+    ui->actionCancel->setEnabled(module->future().canCancel() && module->isRunning());
+    currentFutureWatcher.setFuture(module->future());
+  }
+}
+
+void ctkCLModuleExplorerMainWindow::addModuleTab(const ctkCmdLineModuleReference &moduleRef)
+{
+  ctkCmdLineModuleFrontend* moduleFrontend = this->defaultModuleFrontendFactory->create(moduleRef);
+  this->tabList->addTab(moduleFrontend);
+}
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h
similarity index 57%
rename from Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
rename to Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h
index 5d0f9856cd..481073f611 100644
--- a/Applications/ctkCommandLineModuleExplorer/ctkCLModuleExplorerMainWindow.h
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h
@@ -23,19 +23,23 @@
 #define CTKCLIPLUGINEXPLORERMAINWINDOW_H
 
 #include 
-#include 
-#include 
+#include 
+#include 
 
 #include 
-#include 
+#include 
 #include 
 
+class ctkCmdLineModuleExplorerTabList;
 class ctkCmdLineModuleReference;
+class ctkCmdLineModuleResult;
+class ctkSettingsDialog;
 
 namespace Ui {
-class ctkCLModuleExplorerMainWindow;
+class ctkCmdLineModuleExplorerMainWindow;
 }
 
+
 class ctkCLModuleExplorerMainWindow : public QMainWindow
 {
   Q_OBJECT
@@ -44,29 +48,41 @@ class ctkCLModuleExplorerMainWindow : public QMainWindow
   explicit ctkCLModuleExplorerMainWindow(QWidget *parent = 0);
   ~ctkCLModuleExplorerMainWindow();
 
-  void addModule(const QString& location);
+  void addModule(const QUrl &location);
 
 protected Q_SLOTS:
 
   void on_actionRun_triggered();
+  void on_actionPause_toggled(bool toggled);
+  void on_actionCancel_triggered();
+  void on_actionOptions_triggered();
 
-  void moduleStarted();
-  void moduleFinished();
-  void moduleProgressValueChanged(int);
-  void moduleProgressTextChanged(QString);
+  void checkModulePaused();
+  void currentModuleResumed();
+  void currentModuleCanceled();
+  void currentModuleFinished();
 
-protected:
+  void moduleTabActivated(ctkCmdLineModuleFrontend* module);
 
   void addModuleTab(const ctkCmdLineModuleReference& moduleRef);
   
 private:
 
-  Ui::ctkCLModuleExplorerMainWindow *ui;
+  QScopedPointer ui;
+  QScopedPointer tabList;
+
+  ctkCmdLineModuleFrontendFactory* defaultModuleFrontendFactory;
+  QList moduleFrontendFactories;
+  QList moduleBackends;
 
   ctkCmdLineModuleManager moduleManager;
-  QFutureWatcher* watcher;
 
-  QHash mapTabToModuleRef;
+  QTimer pollPauseTimer;
+  QFutureWatcher currentFutureWatcher;
+
+  ctkCmdLineModuleDirectoryWatcher directoryWatcher;
+
+  ctkSettingsDialog* settingsDialog;
 
 };
 
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui
new file mode 100644
index 0000000000..5465123117
--- /dev/null
+++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui
@@ -0,0 +1,240 @@
+
+
+ ctkCmdLineModuleExplorerMainWindow
+ 
+  
+   
+    0
+    0
+    800
+    600
+   
+  
+  
+   CTK Command Line Module Explorer
+  
+  
+   QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks
+  
+  
+   
+    
+     0
+    
+    
+     
+      
+       -1
+      
+      
+       Qt::ElideMiddle
+      
+      
+       true
+      
+      
+       true
+      
+     
+    
+   
+  
+  
+   
+    
+     0
+     0
+     800
+     25
+    
+   
+   
+    
+     &File
+    
+    
+    
+    
+   
+   
+    
+     &Module
+    
+    
+    
+    
+    
+    
+   
+   
+   
+  
+  
+  
+   
+    toolBar
+   
+   
+    TopToolBarArea
+   
+   
+    false
+   
+   
+   
+   
+  
+  
+   
+    QDockWidget::NoDockWidgetFeatures
+   
+   
+    Modules
+   
+   
+    1
+   
+   
+    
+     
+      0
+     
+     
+      
+       
+        false
+       
+       
+        
+         1
+        
+       
+      
+     
+    
+   
+  
+  
+   
+    QDockWidget::NoDockWidgetFeatures
+   
+   
+    Progress Information
+   
+   
+    1
+   
+   
+    
+     
+      0
+     
+     
+      0
+     
+     
+      
+       
+        
+         4
+        
+        
+         0
+        
+        
+         4
+        
+        
+         0
+        
+        
+         4
+        
+       
+      
+     
+    
+   
+  
+  
+   
+    
+     :/icons/run.png:/icons/run.png
+   
+   
+    Run
+   
+   
+    Run module
+   
+   
+    Ctrl+R
+   
+  
+  
+   
+    
+     :/icons/stop.png:/icons/stop.png
+   
+   
+    &Cancel
+   
+   
+    Cancel module
+   
+   
+    Ctrl+C
+   
+  
+  
+   
+    &Load Module...
+   
+   
+    Load module
+   
+   
+    Ctrl+L
+   
+  
+  
+   
+    E&xit
+   
+  
+  
+   
+    true
+   
+   
+    
+     :/icons/pause.png:/icons/pause.png
+   
+   
+    &Pause
+   
+   
+    Pause module
+   
+   
+    Ctrl+P
+   
+  
+  
+   
+    &Options...
+   
+  
+ 
+ 
+  
+   ctkCmdLineModuleExplorerTreeWidget
+   QTreeWidget
+   
ctkCmdLineModuleExplorerTreeWidget.h
+
+
+ + + + +
diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.cpp new file mode 100644 index 0000000000..6f2c3d2679 --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.cpp @@ -0,0 +1,127 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include + +#include "ctkCmdLineModuleExplorerProgressWidget.h" +#include "ui_ctkCmdLineModuleExplorerProgressWidget.h" + + +ctkCmdLineModuleExplorerProgressWidget::ctkCmdLineModuleExplorerProgressWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::ctkCmdLineModuleExplorerProgressWidget) +{ + ui->setupUi(this); + + // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is + // not emitted directly when the QFuture is paused. Instead, it is emitted after + // resuming the future, after the "resume" signal has been emitted... we use + // a polling aproach instead. + PollPauseTimer.setInterval(300); + connect(&PollPauseTimer, SIGNAL(timeout()), SLOT(checkModulePaused())); + + connect(&FutureWatcher, SIGNAL(started()), SLOT(moduleStarted())); + connect(&FutureWatcher, SIGNAL(canceled()), SLOT(moduleCanceled())); + connect(&FutureWatcher, SIGNAL(finished()), SLOT(moduleFinished())); + connect(&FutureWatcher, SIGNAL(resumed()), SLOT(moduleResumed())); + connect(&FutureWatcher, SIGNAL(progressRangeChanged(int,int)), SLOT(moduleProgressRangeChanged(int,int))); + connect(&FutureWatcher, SIGNAL(progressTextChanged(QString)), ui->ProgressText, SLOT(setText(QString))); + connect(&FutureWatcher, SIGNAL(progressValueChanged(int)), ui->ProgressBar, SLOT(setValue(int))); + + connect(ui->CancelButton, SIGNAL(clicked()), &this->FutureWatcher, SLOT(cancel())); + + PollPauseTimer.start(); +} + +ctkCmdLineModuleExplorerProgressWidget::~ctkCmdLineModuleExplorerProgressWidget() +{ + delete ui; +} + +void ctkCmdLineModuleExplorerProgressWidget::setFuture(const ctkCmdLineModuleFuture &future) +{ + ui->PauseButton->setEnabled(future.canPause()); + ui->CancelButton->setEnabled(future.canCancel()); + FutureWatcher.setFuture(future); +} + +void ctkCmdLineModuleExplorerProgressWidget::on_PauseButton_toggled(bool toggled) +{ + this->FutureWatcher.setPaused(toggled); +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleStarted() +{ + this->ui->ProgressBar->setMaximum(0); +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleCanceled() +{ + this->ui->PauseButton->setEnabled(false); + this->ui->PauseButton->setChecked(false); + this->ui->CancelButton->setEnabled(false); +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleFinished() +{ + this->ui->PauseButton->setEnabled(false); + this->ui->PauseButton->setChecked(false); + this->ui->CancelButton->setEnabled(false); +} + +void ctkCmdLineModuleExplorerProgressWidget::checkModulePaused() +{ + if (this->FutureWatcher.future().isPaused()) + { + if (!ui->PauseButton->isChecked()) + { + ui->PauseButton->setChecked(true); + } + } + else + { + if (ui->PauseButton->isChecked()) + { + ui->PauseButton->setChecked(false); + } + } +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleResumed() +{ + this->ui->PauseButton->setChecked(false); +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleProgressRangeChanged(int progressMin, int progressMax) +{ + this->ui->ProgressBar->setMinimum(progressMin); + this->ui->ProgressBar->setMaximum(progressMax); +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleProgressTextChanged(const QString& progressText) +{ + Q_UNUSED(progressText) +} + +void ctkCmdLineModuleExplorerProgressWidget::moduleProgressValueChanged(int progressValue) +{ + Q_UNUSED(progressValue) +} diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h new file mode 100644 index 0000000000..37e76613c5 --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h @@ -0,0 +1,70 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLORERPROGRESSWIDGET_H +#define CTKCMDLINEMODULEEXPLORERPROGRESSWIDGET_H + + +#include +#include +#include + +class ctkCmdLineModuleFuture; +class ctkCmdLineModuleResult; + +namespace Ui { +class ctkCmdLineModuleExplorerProgressWidget; +} + +class ctkCmdLineModuleExplorerProgressWidget : public QWidget +{ + Q_OBJECT + +public: + + ctkCmdLineModuleExplorerProgressWidget(QWidget *parent = 0); + ~ctkCmdLineModuleExplorerProgressWidget(); + + void setFuture(const ctkCmdLineModuleFuture& future); + +private Q_SLOTS: + + void on_PauseButton_toggled(bool toggled); + + void checkModulePaused(); + + void moduleStarted(); + void moduleCanceled(); + void moduleFinished(); + void moduleResumed(); + void moduleProgressRangeChanged(int progressMin, int progressMax); + void moduleProgressTextChanged(const QString& progressText); + void moduleProgressValueChanged(int progressValue); + +private: + Ui::ctkCmdLineModuleExplorerProgressWidget *ui; + + QFutureWatcher FutureWatcher; + QTimer PollPauseTimer; + +}; + +#endif // CTKCMDLINEMODULEEXPLORERPROGRESSWIDGET_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.ui new file mode 100644 index 0000000000..556f723b1a --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.ui @@ -0,0 +1,79 @@ + + + ctkCmdLineModuleExplorerProgressWidget + + + + 0 + 0 + 400 + 98 + + + + Form + + + + + + TextLabel + + + + + + + + + 0 + + + + + + + ... + + + + :/icons/pause.png:/icons/pause.png + + + true + + + true + + + + + + + ... + + + + :/icons/stop.png:/icons/stop.png + + + true + + + + + + + + + TextLabel + + + + + + + + + + diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp new file mode 100644 index 0000000000..f5a6e8979f --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp @@ -0,0 +1,116 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleExplorerTabList.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +Q_DECLARE_METATYPE(ctkCmdLineModuleFrontendFactory*) + +ctkCmdLineModuleExplorerTabList::ctkCmdLineModuleExplorerTabList(QTabWidget *tabWidget) + : TabWidget(tabWidget) +{ + Q_ASSERT(TabWidget != NULL); + + connect(TabWidget, SIGNAL(currentChanged(int)), SLOT(tabIndexChanged(int))); + connect(TabWidget, SIGNAL(tabCloseRequested(int)), SLOT(tabCloseRequested(int))); +} + +ctkCmdLineModuleExplorerTabList::~ctkCmdLineModuleExplorerTabList() +{ + qDeleteAll(this->TabIndexToFrontend); +} + +ctkCmdLineModuleFrontend* ctkCmdLineModuleExplorerTabList::activeTab() const +{ + int index = this->TabWidget->currentIndex(); + if (index < 0) return NULL; + return this->TabIndexToFrontend[index]; +} + +void ctkCmdLineModuleExplorerTabList::addTab(ctkCmdLineModuleFrontend* moduleFrontend) +{ + QWidget* widget = qobject_cast(moduleFrontend->guiHandle()); + this->TabIndexToFrontend.push_back(moduleFrontend); + int index = this->TabWidget->addTab(widget, moduleFrontend->moduleReference().description().title()); + this->TabWidget->setCurrentIndex(index); +} + +void ctkCmdLineModuleExplorerTabList::tabIndexChanged(int index) +{ + if (index < 0) + { + emit tabActivated(NULL); + return; + } + emit tabActivated(this->TabIndexToFrontend[index]); +} + +void ctkCmdLineModuleExplorerTabList::tabCloseRequested(int index) +{ + ctkCmdLineModuleFrontend* frontend = this->TabIndexToFrontend[index]; + bool removeTab = false; + + if (frontend->isRunning()) + { + if (frontend->future().canCancel()) + { + QMessageBox::StandardButton button = + QMessageBox::warning(QApplication::topLevelWidgets().front(), + "Closing a running module", + "The module '" + frontend->moduleReference().description().title() + "' is still running.\n" + "Closing the tab will cancel the current computation.", + QMessageBox::Ok | QMessageBox::Cancel); + if (button == QMessageBox::Ok) + { + frontend->future().cancel(); + removeTab = true; + } + } + else + { + QMessageBox::information(QApplication::topLevelWidgets().front(), + "Closing not possible", + "The module '" + frontend->moduleReference().description().title() + "' is still running " + "and does not support being canceled."); + } + } + else + { + removeTab = true; + } + + if (removeTab) + { + this->TabIndexToFrontend.removeAt(index); + this->TabWidget->removeTab(index); + delete frontend; + } +} diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h new file mode 100644 index 0000000000..d2476cf72d --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h @@ -0,0 +1,60 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLORERTABLIST_H +#define CTKCMDLINEMODULEEXPLORERTABLIST_H + +class ctkCmdLineModuleFrontend; +class ctkCmdLineModuleManager; + +#include +#include + +class QTabWidget; +class QModelIndex; + +class ctkCmdLineModuleExplorerTabList : public QObject +{ + Q_OBJECT + +public: + + ctkCmdLineModuleExplorerTabList(QTabWidget* tabWidget); + ~ctkCmdLineModuleExplorerTabList(); + + ctkCmdLineModuleFrontend* activeTab() const; + + Q_SLOT void addTab(ctkCmdLineModuleFrontend* frontend); + + Q_SIGNAL void tabActivated(ctkCmdLineModuleFrontend* module); + +private: + + Q_SLOT void tabIndexChanged(int index); + Q_SLOT void tabCloseRequested(int index); + +private: + + QTabWidget* TabWidget; + QList TabIndexToFrontend; +}; + +#endif // CTKCMDLINEMODULEEXPLORERTABLIST_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp new file mode 100644 index 0000000000..a1cb878e03 --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp @@ -0,0 +1,154 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleExplorerTreeWidget.h" + +#include +#include +#include +#include + +#include +#include +#include + +QString ctkCmdLineModuleExplorerTreeWidget::CATEGORY_UNKNOWN = "Uncategorized"; + +class ctkCmdLineModuleTreeWidgetItem : public QTreeWidgetItem +{ +public: + + static const int CmdLineModuleType = 1001; + + ctkCmdLineModuleTreeWidgetItem(const ctkCmdLineModuleReference& moduleRef) + : QTreeWidgetItem(CmdLineModuleType), ModuleRef(moduleRef) + { + init(); + } + + ctkCmdLineModuleTreeWidgetItem(QTreeWidget* parent, const ctkCmdLineModuleReference& moduleRef) + : QTreeWidgetItem(parent, CmdLineModuleType), ModuleRef(moduleRef) + { + init(); + } + + ctkCmdLineModuleTreeWidgetItem(QTreeWidgetItem* parent, const ctkCmdLineModuleReference& moduleRef) + : QTreeWidgetItem(parent, CmdLineModuleType), ModuleRef(moduleRef) + { + init(); + } + + ctkCmdLineModuleReference moduleReference() const + { + return ModuleRef; + } + +private: + + void init() + { + this->setText(0, ModuleRef.description().title() + " [" + ModuleRef.backend()->name() + "]"); + this->setData(0, Qt::UserRole, QVariant::fromValue(ModuleRef)); + } + + ctkCmdLineModuleReference ModuleRef; + +}; + +ctkCmdLineModuleExplorerTreeWidget::ctkCmdLineModuleExplorerTreeWidget(QWidget *parent) + : QTreeWidget(parent) +{ + this->ContextMenu = new QMenu(this); + this->ShowFrontendMenu = this->ContextMenu->addMenu("Create Frontend"); + + this->ContextMenu->addAction("Properties"); + + connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(moduleDoubleClicked(QModelIndex))); +} + +void ctkCmdLineModuleExplorerTreeWidget::setModuleFrontendFactories(const QList &frontendFactories) +{ + this->FrontendFactories = frontendFactories; + + this->ShowFrontendMenu->clear(); + foreach(ctkCmdLineModuleFrontendFactory* factory, this->FrontendFactories) + { + QAction* action = this->ShowFrontendMenu->addAction(factory->name(), this, SLOT(frontendFactoryActionTriggered())); + this->ActionsToFrontendFactoryMap[action] = factory; + action->setToolTip(factory->description()); + } +} + +void ctkCmdLineModuleExplorerTreeWidget::addModuleItem(const ctkCmdLineModuleReference &moduleRef) +{ + QString category = moduleRef.description().category(); + + QTreeWidgetItem* rootItem = NULL; + + if (category.isEmpty()) + { + category = CATEGORY_UNKNOWN; + } + + rootItem = TreeWidgetCategories[category]; + if (rootItem == NULL) + { + // lazily create the root item for the category + rootItem = new QTreeWidgetItem(this); + rootItem->setText(0, category); + TreeWidgetCategories[category] = rootItem; + } + new ctkCmdLineModuleTreeWidgetItem(rootItem, moduleRef); +} + +void ctkCmdLineModuleExplorerTreeWidget::contextMenuEvent(QContextMenuEvent *event) +{ + QTreeWidgetItem* item = this->itemAt(this->viewport()->mapFromGlobal(event->globalPos())); + if (item != NULL && item->type() == ctkCmdLineModuleTreeWidgetItem::CmdLineModuleType) + { + this->ContextReference = item->data(0, Qt::UserRole).value(); + this->ContextMenu->exec(event->globalPos()); + event->accept(); + } + else + { + this->ContextReference = ctkCmdLineModuleReference(); + event->ignore(); + } +} + +void ctkCmdLineModuleExplorerTreeWidget::moduleDoubleClicked(const QModelIndex &index) +{ + QVariant data = index.data(Qt::UserRole); + if (!data.isValid()) return; + + ctkCmdLineModuleReference moduleRef = data.value(); + if (!moduleRef) return; + + emit moduleDoubleClicked(moduleRef); +} + +void ctkCmdLineModuleExplorerTreeWidget::frontendFactoryActionTriggered() +{ + ctkCmdLineModuleFrontendFactory* frontendFactory = this->ActionsToFrontendFactoryMap[static_cast(this->sender())]; + ctkCmdLineModuleFrontend* frontend = frontendFactory->create(this->ContextReference); + emit moduleFrontendCreated(frontend); +} diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h new file mode 100644 index 0000000000..9470708250 --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h @@ -0,0 +1,67 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLORERTREEWIDGET_H +#define CTKCMDLINEMODULEEXPLORERTREEWIDGET_H + +#include + +#include + +class ctkCmdLineModuleFrontend; +class ctkCmdLineModuleFrontendFactory; + +class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget +{ + Q_OBJECT + +public: + + explicit ctkCmdLineModuleExplorerTreeWidget(QWidget* parent = 0); + + void setModuleFrontendFactories(const QList& frontendFactories); + + Q_SLOT void addModuleItem(const ctkCmdLineModuleReference& moduleRef); + + Q_SIGNAL void moduleDoubleClicked(ctkCmdLineModuleReference moduleRef); + Q_SIGNAL void moduleFrontendCreated(ctkCmdLineModuleFrontend* moduleFrontend); + +protected: + + void contextMenuEvent(QContextMenuEvent* event); + +private: + + Q_SLOT void moduleDoubleClicked(const QModelIndex& index); + Q_SLOT void frontendFactoryActionTriggered(); + + static QString CATEGORY_UNKNOWN; + + QMenu* ContextMenu; + QMenu* ShowFrontendMenu; + + ctkCmdLineModuleReference ContextReference; + QList FrontendFactories; + QHash TreeWidgetCategories; + QHash ActionsToFrontendFactoryMap; +}; + +#endif // CTKCMDLINEMODULEEXPLORERTREEWIDGET_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp index f41b785deb..0d2391483b 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp @@ -36,7 +36,7 @@ #include #include -#include "ctkCLModuleExplorerMainWindow.h" +#include "ctkCmdLineModuleExplorerMainWindow.h" int main(int argc, char** argv) { diff --git a/Applications/ctkCommandLineModuleExplorer/resources/ctkCLModuleExplorer.qrc b/Applications/ctkCommandLineModuleExplorer/resources/ctkCmdLineModuleExplorer.qrc similarity index 79% rename from Applications/ctkCommandLineModuleExplorer/resources/ctkCLModuleExplorer.qrc rename to Applications/ctkCommandLineModuleExplorer/resources/ctkCmdLineModuleExplorer.qrc index 29b29ad4aa..5570fc5bdf 100644 --- a/Applications/ctkCommandLineModuleExplorer/resources/ctkCLModuleExplorer.qrc +++ b/Applications/ctkCommandLineModuleExplorer/resources/ctkCmdLineModuleExplorer.qrc @@ -2,5 +2,6 @@ run.png stop.png + pause.png diff --git a/Applications/ctkCommandLineModuleExplorer/resources/pause.png b/Applications/ctkCommandLineModuleExplorer/resources/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..a63d34e17ee277b608f552536dce3a4b8e829d6d GIT binary patch literal 865 zcmV-n1D^beP)z zJ+ItE6o#L3=8ShQC{;nOdt@IY)owmz>;uRi(oW6X@0pst~g5b8vzVYLqY`2Dj>;K}_DzF4c-)uTrr z9r)PrArT^MHi2h9{B#LC0saJ5X9XaFnepP+6){0diIgBlhzZ`gdx3}o+$|S>yaK_Q z@%-hI1f+E6F~Pg{4m|MBsDOkJ6WlCA6DaKi1C&()bpZbFU%vhK-us^s6I?GsGe6JS zwQY5==K<~KI}#wG)HVC$v5B>-Y8w)wdc?<8(jA`#boo&Ms1o9Ea!8aV?SKhYLY+EE z+gi$Uq5u&`2*b%!>MX&YuR&PjI4#%czYhY6{)hVPR7R@(;X;7+OOw&6Irh7TnS+PC207Q33~jffL%o)B(9f% z&^Vgf%Z08z}cdJ#di)djrQZbei1Q3q7^uZ}uFRZyph3Mx<( z+WR4z#^1^T?-l0+HN`naO;A--g`#lXT|Jc_bwGroXo8tyUUBAfbxtW}JqIT8w{Sr4 zCQUGh`8+zWIpEy&_P|7bQ~-kaf^&-ViWLqk9KLWkQ;M1E?dqxgEgUct)a9z2clepZ z&kXa9Vs`AnBz{bQv;yvens@lZDCW7h&-bbPxC4NY`0%|u6f<||^E@U5dKFFO&kCr^ z#p9n}{B|kYSSNWDRcP)le}DcBPyul&e_ZTwdkeTv{vYp82(N&@$R8R^ +#include + +struct ctkCmdLineModuleBackendLocalProcessPrivate +{ + + QString normalizeFlag(const QString& flag) const + { + return flag.trimmed().remove(QRegExp("^-*")); + } + + QStringList commandLineArguments(const QHash& currentValues, + const ctkCmdLineModuleDescription& description) const + { + QStringList cmdLineArgs; + QHash indexedArgs; + + QHashIterator valuesIter(currentValues); + while(valuesIter.hasNext()) + { + valuesIter.next(); + ctkCmdLineModuleParameter parameter = description.parameter(valuesIter.key()); + if (parameter.index() > -1) + { + indexedArgs.insert(parameter.index(), valuesIter.value().toString()); + } + else + { + QString argFlag; + if (parameter.longFlag().isEmpty()) + { + argFlag = QString("-") + this->normalizeFlag(parameter.flag()); + } + else + { + argFlag = QString("--") + this->normalizeFlag(parameter.longFlag()); + } + QStringList args; + if (parameter.multiple()) + { + args = valuesIter.value().toString().split(',', QString::SkipEmptyParts); + } + else if (parameter.tag() == "boolean") + { + if (valuesIter.value().toBool()) + { + cmdLineArgs << argFlag; + } + } + else + { + args.push_back(valuesIter.value().toString()); + } + + foreach(QString arg, args) + { + cmdLineArgs << argFlag << arg; + } + } + } + + QList indexes = indexedArgs.keys(); + qSort(indexes.begin(), indexes.end()); + foreach(int index, indexes) + { + cmdLineArgs << indexedArgs[index]; + } + + return cmdLineArgs; + } +}; + +ctkCmdLineModuleBackendLocalProcess::ctkCmdLineModuleBackendLocalProcess() + : d(new ctkCmdLineModuleBackendLocalProcessPrivate){ +} + +ctkCmdLineModuleBackendLocalProcess::~ctkCmdLineModuleBackendLocalProcess() +{ +} + +QString ctkCmdLineModuleBackendLocalProcess::name() const +{ + return "Local Process"; +} + +QString ctkCmdLineModuleBackendLocalProcess::description() const +{ + return "Runs an executable command line module using a local process."; +} + +QList ctkCmdLineModuleBackendLocalProcess::schemes() const +{ + static QList supportedSchemes = QList() << "file"; + return supportedSchemes; +} + +QByteArray ctkCmdLineModuleBackendLocalProcess::rawXmlDescription(const QUrl &location) +{ + QProcess process; + process.setReadChannel(QProcess::StandardOutput); + process.start(location.toLocalFile(), QStringList("--xml")); + + if (!process.waitForFinished() || process.exitStatus() == QProcess::CrashExit || + process.error() != QProcess::UnknownError) + { + throw ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString()); + } + + process.waitForReadyRead(); + return process.readAllStandardOutput(); +} + +ctkCmdLineModuleFuture ctkCmdLineModuleBackendLocalProcess::run(ctkCmdLineModuleFrontend* frontend) +{ + QStringList args = d->commandLineArguments(frontend->values(), frontend->moduleReference().description()); + + // Instances of ctkCmdLineModuleProcessTask are auto-deleted by the + // thread pool. + ctkCmdLineModuleProcessTask* moduleProcess = + new ctkCmdLineModuleProcessTask(frontend->location().toLocalFile(), args); + return moduleProcess->start(); +} diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h new file mode 100644 index 0000000000..101433ebfa --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h @@ -0,0 +1,56 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKENDLOCALPROCESS_H +#define CTKCMDLINEMODULEBACKENDLOCALPROCESS_H + +#include "ctkCmdLineModuleBackend.h" + +#include "ctkCommandLineModulesBackendLocalProcessExport.h" + +#include + +struct ctkCmdLineModuleBackendLocalProcessPrivate; + +class CTK_CMDLINEMODULEBACKENDLP_EXPORT ctkCmdLineModuleBackendLocalProcess : public ctkCmdLineModuleBackend +{ + +public: + + ctkCmdLineModuleBackendLocalProcess(); + ~ctkCmdLineModuleBackendLocalProcess(); + + virtual QString name() const; + virtual QString description() const; + + virtual QList schemes() const; + + virtual QByteArray rawXmlDescription(const QUrl& location); + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend); + +private: + + QScopedPointer d; + +}; + +#endif // CTKCMDLINEMODULEBACKENDLOCALPROCESS_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp similarity index 100% rename from Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.cpp rename to Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h similarity index 100% rename from Libs/CommandLineModules/Core/ctkCmdLineModuleProcessTask.h rename to Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h diff --git a/Libs/CommandLineModules/Backend/LocalProcess/target_libraries.cmake b/Libs/CommandLineModules/Backend/LocalProcess/target_libraries.cmake new file mode 100644 index 0000000000..139da8221c --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/target_libraries.cmake @@ -0,0 +1,9 @@ +# +# See CMake/ctkMacroGetTargetLibraries.cmake +# +# This file should list the libraries required to build the current CTK libraries +# + +set(target_libraries + CTKCommandLineModulesCore + ) diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 0f3e876293..98cf01fd1e 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -14,13 +14,14 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT") # Source files set(KIT_SRCS + ctkCmdLineModuleBackend.cpp ctkCmdLineModuleDefaultPathBuilder.cpp ctkCmdLineModuleDescription.cpp ctkCmdLineModuleDescription_p.h ctkCmdLineModuleDirectoryWatcher.cpp ctkCmdLineModuleDirectoryWatcher_p.h - ctkCmdLineModule.cpp - ctkCmdLineModuleFactory.cpp + ctkCmdLineModuleFrontend.cpp + ctkCmdLineModuleFrontendFactory.cpp ctkCmdLineModuleFuture.h ctkCmdLineModuleFutureInterface.h ctkCmdLineModuleManager.cpp @@ -29,7 +30,6 @@ set(KIT_SRCS ctkCmdLineModuleParameterGroup_p.h ctkCmdLineModuleParameterParsers_p.h ctkCmdLineModulePathBuilder.cpp - ctkCmdLineModuleProcessTask.cpp ctkCmdLineModuleResult.h ctkCmdLineModuleXmlProgressWatcher.cpp ctkCmdLineModuleReference.cpp @@ -47,9 +47,8 @@ set(KIT_SRCS set(KIT_MOC_SRCS ctkCmdLineModuleDirectoryWatcher.h ctkCmdLineModuleDirectoryWatcher_p.h + ctkCmdLineModuleFrontend.h ctkCmdLineModuleManager.h - ctkCmdLineModule.h - ctkCmdLineModuleProcessTask.h ) qt4_wrap_cpp(_dummy ctkCmdLineModuleXmlProgressWatcher.h) diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModules.qrc b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModules.qrc index 21f2884497..ffbc77342e 100644 --- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModules.qrc +++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModules.qrc @@ -1,7 +1,5 @@ ctkCmdLineModule.xsd - ctkCmdLineModuleXmlToQtUi.xsl - QtDesigner.xsd diff --git a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt index 0f709b9555..cdeb442a1d 100644 --- a/Libs/CommandLineModules/Core/Testing/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/CMakeLists.txt @@ -1,2 +1 @@ -add_subdirectory(Modules) add_subdirectory(Cpp) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 5624ae0dcb..9d51a8b184 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -2,9 +2,7 @@ set(KIT ${PROJECT_NAME}) set(LIBRARY_NAME ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp - ctkCmdLineModuleFutureTest.cpp ctkCmdLineModuleXmlProgressWatcherTest.cpp - ctkCmdLineModuleXslTransformTest.cpp ) set(TestsToRun ${Tests}) @@ -24,9 +22,6 @@ include_directories( set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) -QT4_GENERATE_MOCS( - ctkCmdLineModuleXslTransformTest.cpp - ) set(Tests_UI_CPP) if(TEST_UI_FORMS) QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) @@ -36,13 +31,9 @@ QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES}) add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS}) target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) -add_dependencies(${KIT}CppTests ctkCmdLineTestModules) # # Add Tests # -SIMPLE_TEST(ctkCmdLineModuleFutureTest) SIMPLE_TEST(ctkCmdLineModuleXmlProgressWatcherTest) -SIMPLE_TEST(ctkCmdLineModuleXslTransformTest) - diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp deleted file mode 100644 index e3f0e45b3d..0000000000 --- a/Libs/CommandLineModules/Core/ctkCmdLineModule.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics - - 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 - - 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. - -=============================================================================*/ - -#include "ctkCmdLineModule.h" -#include "ctkCmdLineModuleDescription.h" -#include "ctkCmdLineModuleParameter.h" -#include "ctkCmdLineModuleParameterGroup.h" -#include "ctkCmdLineModuleReference.h" -#include "ctkCmdLineModuleProcessTask.h" -#include "ctkCmdLineModuleFuture.h" - -#include "ctkException.h" - -#include -#include -#include - -struct ctkCmdLineModulePrivate -{ - ctkCmdLineModulePrivate(ctkCmdLineModule* qq, - const ctkCmdLineModuleReference& moduleRef) - : ModuleReference(moduleRef), q(qq) - { - - } - - QString normalizeFlag(const QString& flag) - { - return flag.trimmed().remove(QRegExp("^-*")); - } - - ctkCmdLineModuleReference ModuleReference; - - QList ParameterNames; - - ctkCmdLineModuleFuture Future; - -private: - - ctkCmdLineModule* q; - -}; - - -ctkCmdLineModule::ctkCmdLineModule(const ctkCmdLineModuleReference& moduleRef) - : d(new ctkCmdLineModulePrivate(this, moduleRef)) -{ -} - -ctkCmdLineModule::~ctkCmdLineModule() -{ -} - -QList ctkCmdLineModule::parameterNames() const -{ - if (!d->ParameterNames.isEmpty()) return d->ParameterNames; - - foreach (ctkCmdLineModuleParameterGroup paramGroup, - moduleReference().description().parameterGroups()) - { - foreach (ctkCmdLineModuleParameter param, paramGroup.parameters()) - { - d->ParameterNames.push_back(param.name()); - } - } - return d->ParameterNames; -} - -ctkCmdLineModuleReference ctkCmdLineModule::moduleReference() const -{ - return d->ModuleReference; -} - -QString ctkCmdLineModule::location() const -{ - return d->ModuleReference.location(); -} - -QStringList ctkCmdLineModule::commandLineArguments() const -{ - QStringList cmdLineArgs; - QHash indexedArgs; - - QHash currentValues = values(); - ctkCmdLineModuleDescription description = moduleReference().description(); - QHashIterator valuesIter(currentValues); - while(valuesIter.hasNext()) - { - valuesIter.next(); - ctkCmdLineModuleParameter parameter = description.parameter(valuesIter.key()); - if (parameter.index() > -1) - { - indexedArgs.insert(parameter.index(), valuesIter.value().toString()); - } - else - { - QString argFlag; - if (parameter.longFlag().isEmpty()) - { - argFlag = QString("-") + d->normalizeFlag(parameter.flag()); - } - else - { - argFlag = QString("--") + d->normalizeFlag(parameter.longFlag()); - } - QStringList args; - if (parameter.multiple()) - { - args = valuesIter.value().toString().split(',', QString::SkipEmptyParts); - } - else if (parameter.tag() == "boolean") - { - if (valuesIter.value().toBool()) - { - cmdLineArgs << argFlag; - } - } - else - { - args.push_back(valuesIter.value().toString()); - } - - foreach(QString arg, args) - { - cmdLineArgs << argFlag << arg; - } - } - } - - QList indexes = indexedArgs.keys(); - qSort(indexes.begin(), indexes.end()); - foreach(int index, indexes) - { - cmdLineArgs << indexedArgs[index]; - } - - return cmdLineArgs; -} - -ctkCmdLineModuleFuture ctkCmdLineModule::run() const -{ - QStringList args = commandLineArguments(); - - // Instances of ctkCmdLineModuleProcessTask are auto-deleted by the - // thread pool. - ctkCmdLineModuleProcessTask* moduleProcess = - new ctkCmdLineModuleProcessTask(d->ModuleReference.location(), args); - d->Future = moduleProcess->start(); - return d->Future; -} - -ctkCmdLineModuleFuture ctkCmdLineModule::future() const -{ - return d->Future; -} - -bool ctkCmdLineModule::isRunning() const -{ - return d->Future.isRunning(); -} - -bool ctkCmdLineModule::isPaused() const -{ - return d->Future.isPaused(); -} - -QHash ctkCmdLineModule::values() const -{ - QHash result; - foreach(QString parameterName, parameterNames()) - { - result.insert(parameterName, value(parameterName)); - } - return result; -} - -void ctkCmdLineModule::setValues(const QHash &values) -{ - QHashIterator iter(values); - while(iter.hasNext()) - { - iter.next(); - setValue(iter.key(), iter.value()); - } -} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp similarity index 88% rename from Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp rename to Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp index 1cd22579c1..3af25f827f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp @@ -1,26 +1,26 @@ /*============================================================================= - + Library: CTK - + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics - + 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 - + 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. - + =============================================================================*/ -#include "ctkCmdLineModuleFactory.h" +#include "ctkCmdLineModuleBackend.h" -ctkCmdLineModuleFactory::~ctkCmdLineModuleFactory() +ctkCmdLineModuleBackend::~ctkCmdLineModuleBackend() { } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h new file mode 100644 index 0000000000..7b906e0604 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h @@ -0,0 +1,55 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKEND_H +#define CTKCMDLINEMODULEBACKEND_H + +#include "ctkCommandLineModulesCoreExport.h" + +class ctkCmdLineModuleFrontend; +class ctkCmdLineModuleFuture; + +template class QList; +class QUrl; + +struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend +{ + + ~ctkCmdLineModuleBackend(); + + virtual QString name() const = 0; + virtual QString description() const = 0; + + virtual QList schemes() const = 0; + + virtual QByteArray rawXmlDescription(const QUrl& location) = 0; + +protected: + + friend class ctkCmdLineModuleManager; + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend) = 0; + + //virtual ctkCmdLineModule* createModule(const QString& scheme) = 0; + +}; + +#endif // CTKCMDLINEMODULEBACKEND_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp index 6b8f403608..2e22df9387 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp @@ -21,12 +21,14 @@ #include "ctkCmdLineModuleDirectoryWatcher.h" #include "ctkCmdLineModuleDirectoryWatcher_p.h" #include "ctkCmdLineModuleManager.h" +#include "ctkException.h" #include #include #include #include #include +#include #include #include @@ -105,7 +107,6 @@ ctkCmdLineModuleDirectoryWatcherPrivate::~ctkCmdLineModuleDirectoryWatcherPrivat void ctkCmdLineModuleDirectoryWatcherPrivate::setDebug(bool debug) { this->Debug = debug; - this->ModuleManager->setVerboseOutput(debug); } @@ -313,7 +314,23 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateModuleReferences(const QStri //----------------------------------------------------------------------------- ctkCmdLineModuleReference ctkCmdLineModuleDirectoryWatcherPrivate::loadModule(const QString& pathToExecutable) { - ctkCmdLineModuleReference ref = this->ModuleManager->registerModule(pathToExecutable); + ctkCmdLineModuleReference ref; + try + { + ref = this->ModuleManager->registerModule(QUrl::fromLocalFile(pathToExecutable)); + } + catch (const ctkIllegalStateException& e) + { + e.rethrow(); + } + catch (const ctkException& e) + { + if (this->Debug) + { + qWarning() << e; + } + } + if (ref) { this->MapFileNameToReference[pathToExecutable] = ref; @@ -325,7 +342,7 @@ ctkCmdLineModuleReference ctkCmdLineModuleDirectoryWatcherPrivate::loadModule(co //----------------------------------------------------------------------------- void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModule(const QString& pathToExecutable) { - ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(pathToExecutable); + ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(QUrl::fromLocalFile(pathToExecutable)); if (ref) { this->ModuleManager->unregisterModule(ref); diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp new file mode 100644 index 0000000000..700f7f717c --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp @@ -0,0 +1,119 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFrontend.h" + +#include "ctkCmdLineModuleDescription.h" +#include "ctkCmdLineModuleParameter.h" +#include "ctkCmdLineModuleParameterGroup.h" +#include "ctkCmdLineModuleReference.h" +#include "ctkCmdLineModuleFuture.h" + +#include + +struct ctkCmdLineModuleFrontendPrivate +{ + ctkCmdLineModuleFrontendPrivate(const ctkCmdLineModuleReference& moduleRef) + : ModuleReference(moduleRef) + { + } + + ctkCmdLineModuleReference ModuleReference; + + QList ParameterNames; + + ctkCmdLineModuleFuture Future; +}; + + +ctkCmdLineModuleFrontend::ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef) + : d(new ctkCmdLineModuleFrontendPrivate(moduleRef)) +{ +} + +void ctkCmdLineModuleFrontend::setFuture(const ctkCmdLineModuleFuture &future) +{ + d->Future = future; +} + +ctkCmdLineModuleFrontend::~ctkCmdLineModuleFrontend() +{ +} + +QList ctkCmdLineModuleFrontend::parameterNames() const +{ + if (!d->ParameterNames.isEmpty()) return d->ParameterNames; + + foreach (ctkCmdLineModuleParameterGroup paramGroup, + moduleReference().description().parameterGroups()) + { + foreach (ctkCmdLineModuleParameter param, paramGroup.parameters()) + { + d->ParameterNames.push_back(param.name()); + } + } + return d->ParameterNames; +} + +ctkCmdLineModuleReference ctkCmdLineModuleFrontend::moduleReference() const +{ + return d->ModuleReference; +} + +QUrl ctkCmdLineModuleFrontend::location() const +{ + return d->ModuleReference.location(); +} + +ctkCmdLineModuleFuture ctkCmdLineModuleFrontend::future() const +{ + return d->Future; +} + +bool ctkCmdLineModuleFrontend::isRunning() const +{ + return d->Future.isRunning(); +} + +bool ctkCmdLineModuleFrontend::isPaused() const +{ + return d->Future.isPaused(); +} + +QHash ctkCmdLineModuleFrontend::values() const +{ + QHash result; + foreach(QString parameterName, parameterNames()) + { + result.insert(parameterName, value(parameterName)); + } + return result; +} + +void ctkCmdLineModuleFrontend::setValues(const QHash &values) +{ + QHashIterator iter(values); + while(iter.hasNext()) + { + iter.next(); + setValue(iter.key(), iter.value()); + } +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModule.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h similarity index 73% rename from Libs/CommandLineModules/Core/ctkCmdLineModule.h rename to Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 14a84b91c0..453d002dcb 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModule.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -1,68 +1,64 @@ /*============================================================================= - + Library: CTK - + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics - + 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 - + 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 CTKCMDLINEMODULE_H -#define CTKCMDLINEMODULE_H +#ifndef CTKCMDLINEMODULEFRONTEND_H +#define CTKCMDLINEMODULEFRONTEND_H #include "ctkCommandLineModulesCoreExport.h" #include template class QHash; +class QUrl; -class ctkCmdLineModuleResult; class ctkCmdLineModuleFuture; class ctkCmdLineModuleReference; -class ctkCmdLineModulePrivate; +class ctkCmdLineModuleFrontendPrivate; /** * \ingroup CommandLineModulesCore */ -class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModule : public QObject +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject { Q_OBJECT public: - ~ctkCmdLineModule(); + ~ctkCmdLineModuleFrontend(); virtual QObject* guiHandle() const = 0; virtual QVariant value(const QString& parameter) const = 0; virtual void setValue(const QString& parameter, const QVariant& value) = 0; - virtual QList parameterNames() const; + virtual ctkCmdLineModuleFuture future() const; - virtual QHash values() const; - virtual void setValues(const QHash& values); + QUrl location() const; ctkCmdLineModuleReference moduleReference() const; - QString location() const; - - QStringList commandLineArguments() const; - - ctkCmdLineModuleFuture run() const; + virtual QList parameterNames() const; - ctkCmdLineModuleFuture future() const; + virtual QHash values() const; + virtual void setValues(const QHash& values); bool isRunning() const; bool isPaused() const; @@ -71,14 +67,19 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModule : public QObject protected: - ctkCmdLineModule(const ctkCmdLineModuleReference& moduleRef); + ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef); + + void setFuture(const ctkCmdLineModuleFuture& future); private: + Q_DISABLE_COPY(ctkCmdLineModuleFrontend) + + friend class ctkCmdLineModuleManager; friend class ctkCmdLineModulePrivate; - QScopedPointer d; + QScopedPointer d; }; -#endif // CTKCMDLINEMODULE_H +#endif // CTKCMDLINEMODULEFRONTEND_H diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp similarity index 78% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp rename to Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp index fe56cb7014..502a2c5c4f 100644 --- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleFactoryQtGui.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp @@ -19,11 +19,9 @@ =============================================================================*/ -#include "ctkCmdLineModuleFactoryQtGui.h" -#include "ctkCmdLineModuleQtGui_p.h" +#include "ctkCmdLineModuleFrontendFactory.h" -ctkCmdLineModule* -ctkCmdLineModuleFactoryQtGui::create(const ctkCmdLineModuleReference& moduleRef) + +ctkCmdLineModuleFrontendFactory::~ctkCmdLineModuleFrontendFactory() { - return new ctkCmdLineModuleQtGui(moduleRef); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h similarity index 67% rename from Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h rename to Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h index 69438c7b54..848cb718e6 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFactory.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h @@ -1,40 +1,43 @@ /*============================================================================= - + Library: CTK - + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics - + 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 - + 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 CTKCMDLINEMODULEFACTORY_H -#define CTKCMDLINEMODULEFACTORY_H +#ifndef CTKCMDLINEMODULEFRONTENDFACTORY_H +#define CTKCMDLINEMODULEFRONTENDFACTORY_H #include "ctkCommandLineModulesCoreExport.h" -class ctkCmdLineModule; +class ctkCmdLineModuleFrontend; class ctkCmdLineModuleReference; /** * \ingroup CommandLineModulesCore */ -struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFactory +struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontendFactory { - virtual ~ctkCmdLineModuleFactory(); + virtual ~ctkCmdLineModuleFrontendFactory(); + + virtual QString name() const = 0; + virtual QString description() const = 0; - virtual ctkCmdLineModule* create(const ctkCmdLineModuleReference& module) = 0; + virtual ctkCmdLineModuleFrontend* create(const ctkCmdLineModuleReference& moduleRef) = 0; }; -#endif // CTKCMDLINEMODULEFACTORY_H +#endif // CTKCMDLINEMODULEFRONTENDFACTORY_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 6246ea1d78..11ca3e96e8 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -21,91 +21,111 @@ #include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleBackend.h" +#include "ctkCmdLineModuleFrontend.h" +#include "ctkCmdLineModuleFuture.h" #include "ctkCmdLineModuleXmlValidator.h" #include "ctkCmdLineModuleReference.h" #include "ctkCmdLineModuleReference_p.h" -#include "ctkCmdLineModuleFactory.h" #include #include #include +#include +#include +#include -#include #include struct ctkCmdLineModuleManagerPrivate { - ctkCmdLineModuleManagerPrivate() - : Verbose(false) + ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode) + : ValidationMode(mode) {} - ctkCmdLineModuleFactory* InstanceFactory; + void checkBackends(const QUrl& location) + { + if (!this->SchemeToBackend.contains(location.scheme())) + { + throw ctkInvalidArgumentException(QString("No suitable backend registered for module at ") + location.toString()); + } + } - QHash LocationToRef; + QHash SchemeToBackend; + QHash LocationToRef; - bool Verbose; + ctkCmdLineModuleManager::ValidationMode ValidationMode; }; -ctkCmdLineModuleManager::ctkCmdLineModuleManager(ctkCmdLineModuleFactory *instanceFactory, - ValidationMode validationMode) - : d(new ctkCmdLineModuleManagerPrivate) +ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode) + : d(new ctkCmdLineModuleManagerPrivate(validationMode)) { - d->InstanceFactory = instanceFactory; } ctkCmdLineModuleManager::~ctkCmdLineModuleManager() { } -void ctkCmdLineModuleManager::setVerboseOutput(bool verbose) +void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend) { - d->Verbose = verbose; -} + QList supportedSchemes = backend->schemes(); -bool ctkCmdLineModuleManager::verboseOutput() const -{ - return d->Verbose; + // Check if there is already a backound registerd for any of the + // supported schemes. We only supported one backend per scheme. + foreach (QString scheme, supportedSchemes) + { + if (d->SchemeToBackend.contains(scheme)) + { + throw ctkInvalidArgumentException(QString("A backend for scheme %1 is already registered.").arg(scheme)); + } + } + + // All good + foreach (QString scheme, supportedSchemes) + { + d->SchemeToBackend[scheme] = backend; + } } ctkCmdLineModuleReference -ctkCmdLineModuleManager::registerModule(const QString& location) +ctkCmdLineModuleManager::registerModule(const QUrl &location) { - QProcess process; - process.setReadChannel(QProcess::StandardOutput); - process.start(location, QStringList("--xml")); + d->checkBackends(location); - ctkCmdLineModuleReference ref; - ref.d->Location = location; - if (!process.waitForFinished() || process.exitStatus() == QProcess::CrashExit || - process.error() != QProcess::UnknownError) + QByteArray xml = d->SchemeToBackend[location.scheme()]->rawXmlDescription(location); + + if (xml.isEmpty()) { - if(d->Verbose) - { - qWarning() << "The executable at" << location << "could not be started:" << process.errorString(); - } - return ref; + throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString()); } - process.waitForReadyRead(); - QByteArray xml = process.readAllStandardOutput(); - - // validate the outputted xml description - QBuffer input(&xml); - input.open(QIODevice::ReadOnly); + ctkCmdLineModuleReference ref; + ref.d->Location = location; + ref.d->RawXmlDescription = xml; + ref.d->Backend = d->SchemeToBackend[location.scheme()]; - ctkCmdLineModuleXmlValidator validator(&input); - if (!validator.validateInput()) + if (d->ValidationMode != SKIP_VALIDATION) { - if(d->Verbose) + // validate the outputted xml description + QBuffer input(&xml); + input.open(QIODevice::ReadOnly); + + ctkCmdLineModuleXmlValidator validator(&input); + if (!validator.validateInput()) { - qWarning() << validator.errorString(); + if (d->ValidationMode == STRICT_VALIDATION) + { + throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2") + .arg(location.toString()).arg(validator.errorString())); + } + else + { + ref.d->XmlValidationErrorString = validator.errorString(); + } } - return ref; } - ref.d->RawXmlDescription = xml; - d->LocationToRef[location] = ref; emit moduleRegistered(ref); @@ -118,7 +138,7 @@ void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& emit moduleUnregistered(ref); } -ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QString& location) const +ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const { return d->LocationToRef[location]; } @@ -128,8 +148,11 @@ QList ctkCmdLineModuleManager::moduleReferences() con return d->LocationToRef.values(); } -ctkCmdLineModule* -ctkCmdLineModuleManager::createModule(const ctkCmdLineModuleReference& moduleRef) +ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend) { - return d->InstanceFactory->create(moduleRef); + d->checkBackends(frontend->location()); + + ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend); + frontend->setFuture(future); + return future; } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h index beef55cc23..3b7b3b00ce 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h @@ -28,9 +28,11 @@ #include #include "ctkCmdLineModuleReference.h" -struct ctkCmdLineModuleFactory; +struct ctkCmdLineModuleBackend; +struct ctkCmdLineModuleFrontendFactory; +class ctkCmdLineModuleFrontend; +class ctkCmdLineModuleFuture; -class ctkCmdLineModule; class ctkCmdLineModuleManagerPrivate; /** @@ -54,21 +56,19 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject WEAK_VALIDATION }; - ctkCmdLineModuleManager(ctkCmdLineModuleFactory* descriptionFactory, - ValidationMode = STRICT_VALIDATION); + ctkCmdLineModuleManager(ValidationMode = STRICT_VALIDATION); ~ctkCmdLineModuleManager(); - void setVerboseOutput(bool verbose); - bool verboseOutput() const; + void registerBackend(ctkCmdLineModuleBackend* backend); - ctkCmdLineModuleReference registerModule(const QString& location); + ctkCmdLineModuleReference registerModule(const QUrl& location); void unregisterModule(const ctkCmdLineModuleReference& moduleRef); - ctkCmdLineModuleReference moduleReference(const QString& location) const; + ctkCmdLineModuleReference moduleReference(const QUrl& location) const; QList moduleReferences() const; - ctkCmdLineModule* createModule(const ctkCmdLineModuleReference& moduleRef); + ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend); Q_SIGNALS: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp index c59ffc5521..ce38e60374 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp @@ -25,6 +25,12 @@ #include + +ctkCmdLineModuleReferencePrivate::ctkCmdLineModuleReferencePrivate() + : Backend(NULL) +{ +} + ctkCmdLineModuleDescription ctkCmdLineModuleReferencePrivate::description() const { // Lazy creation. The title is a required XML element. @@ -72,7 +78,17 @@ QByteArray ctkCmdLineModuleReference::rawXmlDescription() const return d->RawXmlDescription; } -QString ctkCmdLineModuleReference::location() const +QString ctkCmdLineModuleReference::xmlValidationErrorString() const +{ + return d->XmlValidationErrorString; +} + +QUrl ctkCmdLineModuleReference::location() const { return d->Location; } + +ctkCmdLineModuleBackend *ctkCmdLineModuleReference::backend() const +{ + return d->Backend; +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index d2fc07db7b..ce3f2bb906 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -27,6 +27,7 @@ #include #include +struct ctkCmdLineModuleBackend; class ctkCmdLineModuleDescription; class ctkCmdLineModuleReferencePrivate; @@ -49,7 +50,11 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference QByteArray rawXmlDescription() const; - QString location() const; + QString xmlValidationErrorString() const; + + QUrl location() const; + + ctkCmdLineModuleBackend* backend() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h index 48ea8d1bf2..224e5f059d 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference_p.h @@ -25,14 +25,20 @@ #include #include -#include +#include + +struct ctkCmdLineModuleBackend; struct ctkCmdLineModuleReferencePrivate : public QSharedData { + ctkCmdLineModuleReferencePrivate(); + ctkCmdLineModuleDescription description() const; - QString Location; + ctkCmdLineModuleBackend* Backend; + QUrl Location; QByteArray RawXmlDescription; + QString XmlValidationErrorString; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp index b41964c8ab..f9329aecf7 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp @@ -1,33 +1,38 @@ -/*=================================================================== - -BlueBerry Platform +/*============================================================================= -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Library: CTK -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -See LICENSE.txt or http://www.mitk.org for details. + 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 + + 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. + +=============================================================================*/ #include "ctkCmdLineModuleRunException.h" -ctkCmdLineModuleRunException::ctkCmdLineModuleRunException( - const QString& location, int errorCode, const QString &errorString) +#include + +ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, int errorCode, const QString &errorString) : QtConcurrent::Exception(), - ctkException(QString("Running module \"%1\" failed with code %2: %3").arg(location).arg(errorCode).arg(errorString)), + ctkException(QString("Running module \"%1\" failed with code %2: %3").arg(location.toString()).arg(errorCode).arg(errorString)), Location(location), ErrorCode(errorCode), ErrorString(errorString) { } -ctkCmdLineModuleRunException::ctkCmdLineModuleRunException( - const QString& location, int errorCode, const QString &errorString, +ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, int errorCode, const QString &errorString, const ctkCmdLineModuleRunException& cause) - : QtConcurrent::Exception(), ctkException(location, cause), + : QtConcurrent::Exception(), ctkException(location.toString(), cause), Location(location), ErrorCode(errorCode), ErrorString(errorString) { } @@ -42,7 +47,7 @@ ctkCmdLineModuleRunException::~ctkCmdLineModuleRunException() throw() { } -QString ctkCmdLineModuleRunException::location() const throw() +QUrl ctkCmdLineModuleRunException::location() const throw() { return Location; } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h index 4e8e68ab4c..ef766e1d7e 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h @@ -1,18 +1,23 @@ -/*=================================================================== - -BlueBerry Platform +/*============================================================================= -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Library: CTK -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -See LICENSE.txt or http://www.mitk.org for details. + 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 + + 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 CTKCMDLINEMODULERUNEXCEPTION_H #define CTKCMDLINEMODULERUNEXCEPTION_H @@ -28,18 +33,19 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleRunException { public: - explicit ctkCmdLineModuleRunException(const QString& location, int errorCode, + explicit ctkCmdLineModuleRunException(const QUrl& location, int errorCode, const QString& errorString); - ctkCmdLineModuleRunException(const QString& location, int errorCode, + ctkCmdLineModuleRunException(const QUrl& location, int errorCode, const QString& errorString, const ctkCmdLineModuleRunException& cause); + ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o); ctkCmdLineModuleRunException& operator=(const ctkCmdLineModuleRunException& o); ~ctkCmdLineModuleRunException() throw(); - QString location() const throw(); + QUrl location() const throw(); int errorCode() const throw(); QString errorString() const throw(); @@ -52,9 +58,9 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleRunException private: - QString Location; - int ErrorCode; - QString ErrorString; + const QUrl Location; + const int ErrorCode; + const QString ErrorString; }; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index f711f1ad71..0659cf0942 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -1,18 +1,23 @@ -/*=================================================================== - -BlueBerry Platform +/*============================================================================= -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Library: CTK -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -See LICENSE.txt or http://www.mitk.org for details. + 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 + + 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. + +=============================================================================*/ #include "ctkCmdLineModuleXmlProgressWatcher.h" diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h index d1eb6b99d7..e6f489fd81 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h @@ -1,18 +1,23 @@ -/*=================================================================== - -BlueBerry Platform +/*============================================================================= -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. + Library: CTK -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics -See LICENSE.txt or http://www.mitk.org for details. + 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 + + 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 CTKCMDLINEMODULEXMLPROGRESSWATCHER_H #define CTKCMDLINEMODULEXMLPROGRESSWATCHER_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp index 47590fbc74..14e91c3544 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp @@ -183,20 +183,20 @@ bool ctkCmdLineModuleXslTransform::transform() return false; } - QIODevice* transformation = d->Transformation; - QScopedPointer defaultTransform(new QFile(":/ctkCmdLineModuleXmlToQtUi.xsl")); - if (!transformation) + if (!d->Transformation) { - transformation = defaultTransform.data(); - transformation->open(QIODevice::ReadOnly); + d->ErrorStr = "No XSL transformation set."; + return false; } - QString query(transformation->readAll()); + + d->Transformation->open(QIODevice::ReadOnly); + QString query(d->Transformation->readAll()); QString extra; foreach(QIODevice* extraIODevice, d->ExtraTransformations) - { + { extraIODevice->open(QIODevice::ReadOnly); extra += extraIODevice->readAll(); - } + } query.replace("", extra); #if 0 qDebug() << query; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h index 11efa6dafa..bcff75b062 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h @@ -73,6 +73,15 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform */ bool transform(); + /** + * @brief Sets the XSL transformation. + * + * Use this method to set the XSL transformation for this instance. Trying + * to transform the input without setting a transformation will result in + * runtime errors. + * + * @param The XSL transformation. + */ void setXslTransformation(QIODevice* transformation); /** @@ -81,7 +90,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform * This can be used to potentially overwrite templates. * To avoid ambiguity, specify a priority > 1 in your overwriting templates * - * @return + * \param transformation Extra XSL transformation fragment. */ void setXslExtraTransformation(QIODevice* transformation); void setXslExtraTransformations(const QList& transformations); diff --git a/Libs/CommandLineModules/QtGui/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt similarity index 86% rename from Libs/CommandLineModules/QtGui/CMakeLists.txt rename to Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt index 45fadf1664..cd06b54758 100644 --- a/Libs/CommandLineModules/QtGui/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt @@ -1,4 +1,4 @@ -project(CTKCommandLineModulesQtGui) +project(CTKCommandLineModulesFrontendQtGui) # # 3rd party dependencies @@ -14,9 +14,8 @@ set(KIT_export_directive "CTK_CMDLINEMODULEQTGUI_EXPORT") # Source files set(KIT_SRCS - ctkCmdLineModuleFactoryQtGui.cpp - ctkCmdLineModuleQtGui_p.h - ctkCmdLineModuleQtGui.cpp + ctkCmdLineModuleFrontendFactoryQtGui.cpp + ctkCmdLineModuleFrontendQtGui.cpp ctkCmdLineModuleMenuFactoryQtGui.cpp ctkCmdLineModuleObjectTreeWalker_p.h ctkCmdLineModuleObjectTreeWalker.cpp @@ -32,7 +31,7 @@ set(KIT_UI_FORMS # Resources set(KIT_resources - + Resources/ctkCmdLineModulesFrontendQtGui.qrc ) set(QT_USE_QTUITOOLS 1) @@ -66,5 +65,5 @@ endif() # Testing if(BUILD_TESTING) -# add_subdirectory(Testing) + add_subdirectory(Testing) endif() diff --git a/Libs/CommandLineModules/Core/Resources/QtDesigner.xsd b/Libs/CommandLineModules/Frontend/QtGui/Resources/QtDesigner.xsd similarity index 100% rename from Libs/CommandLineModules/Core/Resources/QtDesigner.xsd rename to Libs/CommandLineModules/Frontend/QtGui/Resources/QtDesigner.xsd diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl similarity index 100% rename from Libs/CommandLineModules/Core/Resources/ctkCmdLineModuleXmlToQtUi.xsl rename to Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModulesFrontendQtGui.qrc b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModulesFrontendQtGui.qrc new file mode 100644 index 0000000000..04d5ffd57e --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModulesFrontendQtGui.qrc @@ -0,0 +1,6 @@ + + + ctkCmdLineModuleXmlToQtUi.xsl + QtDesigner.xsd + + diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/Testing/CMakeLists.txt new file mode 100644 index 0000000000..d6112f6eb2 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(Cpp) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt new file mode 100644 index 0000000000..a6ca7d754b --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt @@ -0,0 +1,43 @@ +set(KIT ${PROJECT_NAME}) +set(LIBRARY_NAME ${PROJECT_NAME}) + +create_test_sourcelist(Tests ${KIT}CppTests.cpp + ctkCmdLineModuleQtXslTransformTest.cpp + ) + +set(TestsToRun ${Tests}) +remove(TestsToRun ${KIT}CppTests.cpp) + +set(Tests_SRCS ${Tests_SRCS} + +) +set(Tests_MOC_SRCS ${Tests_MOC_SRCS} + +) + +include_directories( + ${CMAKE_SOURCE_DIR}/Libs/Testing + ${CMAKE_CURRENT_BINARY_DIR} + ) + +set(Tests_MOC_CPP) +QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) +QT4_GENERATE_MOCS( + ctkCmdLineModuleQtXslTransformTest.cpp + ) +set(Tests_UI_CPP) +if(TEST_UI_FORMS) + QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) +endif() +set(Tests_RESOURCES_SRCS) +QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES}) + +add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS}) +target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) + +# +# Add Tests +# + +SIMPLE_TEST(ctkCmdLineModuleQtXslTransformTest) + diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp similarity index 91% rename from Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp rename to Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp index 6907d85f5d..c3264c4111 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXslTransformTest.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp @@ -25,11 +25,12 @@ #include // CTK includes +#include "ctkCmdLineModuleFrontendFactoryQtGui.h" #include "ctkCmdLineModuleXslTransform.h" #include "ctkTest.h" // ---------------------------------------------------------------------------- -class ctkCmdLineModuleXslTransformTester: public QObject +class ctkCmdLineModuleQtXslTransformTester: public QObject { Q_OBJECT private slots: @@ -170,10 +171,13 @@ QString integerWidgetSpinBoxFooter = // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testTransform() +void ctkCmdLineModuleQtXslTransformTester::testTransform() { ctkCmdLineModuleXslTransform transformer; + QFile transformation(":/ctkCmdLineModuleXmlToQtUi.xsl"); + transformer.setXslTransformation(&transformation); + QFETCH(QString, input); QByteArray inputByteArray = input.toUtf8(); QBuffer inputBuffer(&inputByteArray); @@ -200,7 +204,7 @@ void ctkCmdLineModuleXslTransformTester::testTransform() } // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testTransform_data() +void ctkCmdLineModuleQtXslTransformTester::testTransform_data() { QTest::addColumn("input"); QTest::addColumn("expectedSuccess"); @@ -248,10 +252,13 @@ void ctkCmdLineModuleXslTransformTester::testTransform_data() } // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testBindVariable() +void ctkCmdLineModuleQtXslTransformTester::testBindVariable() { ctkCmdLineModuleXslTransform transformer; + QFile transformation(":/ctkCmdLineModuleXmlToQtUi.xsl"); + transformer.setXslTransformation(&transformation); + QFETCH(QString, input); QByteArray inputArray(input.toUtf8()); QBuffer inputBuffer(&inputArray); @@ -274,7 +281,7 @@ void ctkCmdLineModuleXslTransformTester::testBindVariable() } // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testBindVariable_data() +void ctkCmdLineModuleQtXslTransformTester::testBindVariable_data() { QTest::addColumn("input"); QTest::addColumn("variableName"); @@ -306,10 +313,13 @@ void ctkCmdLineModuleXslTransformTester::testBindVariable_data() } // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation() +void ctkCmdLineModuleQtXslTransformTester::testXslExtraTransformation() { ctkCmdLineModuleXslTransform transformer; + QFile transformation(":/ctkCmdLineModuleXmlToQtUi.xsl"); + transformer.setXslTransformation(&transformation); + QFETCH(QString, input); QByteArray inputArray(input.toUtf8()); QBuffer inputBuffer(&inputArray); @@ -335,7 +345,7 @@ void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation() } // ---------------------------------------------------------------------------- -void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation_data() +void ctkCmdLineModuleQtXslTransformTester::testXslExtraTransformation_data() { QString extra = "\n" @@ -442,5 +452,17 @@ void ctkCmdLineModuleXslTransformTester::testXslExtraTransformation_data() } // ---------------------------------------------------------------------------- -CTK_TEST_MAIN(ctkCmdLineModuleXslTransformTest) -#include "moc_ctkCmdLineModuleXslTransformTest.cpp" +//CTK_TEST_MAIN(ctkCmdLineModuleQtXslTransformTest) +int ctkCmdLineModuleQtXslTransformTest(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QTEST_DISABLE_KEYPAD_NAVIGATION + + // Introduce a dummy linker dependency to CTKCommandLineModulesFrontendQtGui to + // get access to the ctkCmdLineModuleXmlToQtUi.xsl resource. + ctkCmdLineModuleFrontendFactoryQtGui guiFactory; + + ctkCmdLineModuleQtXslTransformTester tc; + return QTest::qExec(&tc, argc, argv); +} +#include "moc_ctkCmdLineModuleQtXslTransformTest.cpp" diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp new file mode 100644 index 0000000000..ff565e4485 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp @@ -0,0 +1,40 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFrontendFactoryQtGui.h" + +#include "ctkCmdLineModuleFrontendQtGui.h" + +ctkCmdLineModuleFrontendQtGui *ctkCmdLineModuleFrontendFactoryQtGui::create(const ctkCmdLineModuleReference &moduleRef) +{ + return new ctkCmdLineModuleFrontendQtGui(moduleRef); +} + + +QString ctkCmdLineModuleFrontendFactoryQtGui::name() const +{ + return "Qt Gui"; +} + +QString ctkCmdLineModuleFrontendFactoryQtGui::description() const +{ + return "A frontend using the QtGui library."; +} diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h new file mode 100644 index 0000000000..8fde216475 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h @@ -0,0 +1,41 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFRONTENDFACTORYQTGUI_H +#define CTKCMDLINEMODULEFRONTENDFACTORYQTGUI_H + +#include "ctkCommandLineModulesFrontendQtGuiExport.h" + +#include "ctkCmdLineModuleFrontendFactory.h" +#include "ctkCmdLineModuleFrontendQtGui.h" + +class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendFactoryQtGui : public ctkCmdLineModuleFrontendFactory +{ + +public: + + virtual QString name() const; + virtual QString description() const; + + virtual ctkCmdLineModuleFrontendQtGui* create(const ctkCmdLineModuleReference& moduleRef); +}; + +#endif // CTKCMDLINEMODULEFRONTENDFACTORYQTGUI_H diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp similarity index 68% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index 6cffd919e1..63c06fa8d8 100644 --- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -1,30 +1,32 @@ /*============================================================================= - + Library: CTK - + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics - + 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 - + 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. - + =============================================================================*/ -#include "ctkCmdLineModuleQtGui_p.h" +#include "ctkCmdLineModuleFrontendQtGui.h" + #include "ctkCmdLineModuleReference.h" #include "ctkCmdLineModuleXslTransform.h" #include "ctkCmdLineModuleObjectTreeWalker_p.h" #include +#include #include #include #include @@ -32,15 +34,15 @@ #include -ctkCmdLineModuleQtGui::ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef) - : ctkCmdLineModule(moduleRef), - WidgetTree(NULL) +ctkCmdLineModuleFrontendQtGui::ctkCmdLineModuleFrontendQtGui(const ctkCmdLineModuleReference& moduleRef) + : ctkCmdLineModuleFrontend(moduleRef), + Widget(NULL) { } -QObject* ctkCmdLineModuleQtGui::guiHandle() const +QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const { - if (WidgetTree) return WidgetTree; + if (Widget) return Widget; QBuffer input; input.setData(moduleReference().rawXmlDescription()); @@ -48,6 +50,8 @@ QObject* ctkCmdLineModuleQtGui::guiHandle() const QBuffer uiForm; uiForm.open(QIODevice::ReadWrite); ctkCmdLineModuleXslTransform xslTransform(&input, &uiForm); + QFile qtGuiTransformation(":/ctkCmdLineModuleXmlToQtUi.xsl"); + xslTransform.setXslTransformation(&qtGuiTransformation); if (!xslTransform.transform()) { // maybe throw an exception @@ -63,15 +67,15 @@ QObject* ctkCmdLineModuleQtGui::guiHandle() const uiLoader.addPluginPath(appPath + "/../designer"); } #endif - WidgetTree = uiLoader.load(&uiForm); - return WidgetTree; + this->Widget = uiLoader.load(&uiForm); + return this->Widget; } -QVariant ctkCmdLineModuleQtGui::value(const QString ¶meter) const +QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter) const { - if (!WidgetTree) return QVariant(); + if (!this->Widget) return QVariant(); - ctkCmdLineModuleObjectTreeWalker reader(WidgetTree); + ctkCmdLineModuleObjectTreeWalker reader(this->Widget); while(reader.readNextParameter()) { if(reader.name() == parameter) @@ -82,11 +86,11 @@ QVariant ctkCmdLineModuleQtGui::value(const QString ¶meter) const return QVariant(); } -void ctkCmdLineModuleQtGui::setValue(const QString ¶meter, const QVariant &value) +void ctkCmdLineModuleFrontendQtGui::setValue(const QString ¶meter, const QVariant &value) { - if (!WidgetTree) return; + if (!this->Widget) return; - ctkCmdLineModuleObjectTreeWalker walker(WidgetTree); + ctkCmdLineModuleObjectTreeWalker walker(this->Widget); while(walker.readNextParameter()) { if(walker.name() == parameter && walker.value() != value) @@ -97,7 +101,7 @@ void ctkCmdLineModuleQtGui::setValue(const QString ¶meter, const QVariant &v } } -QList ctkCmdLineModuleQtGui::parameterNames() const +QList ctkCmdLineModuleFrontendQtGui::parameterNames() const { if (!ParameterNames.empty()) return ParameterNames; @@ -105,9 +109,9 @@ QList ctkCmdLineModuleQtGui::parameterNames() const // if it has already created (otherwise fall back to the superclass // implementation. // This avoids creating a ctkCmdLineModuleDescription instance. - if (WidgetTree == 0) return ctkCmdLineModule::parameterNames(); + if (this->Widget == 0) return ctkCmdLineModuleFrontend::parameterNames(); - ctkCmdLineModuleObjectTreeWalker walker(WidgetTree); + ctkCmdLineModuleObjectTreeWalker walker(this->Widget); while(walker.readNextParameter()) { ParameterNames.push_back(walker.name()); diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h similarity index 74% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index 00f8794b93..bc68650f12 100644 --- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleQtGui_p.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -1,39 +1,39 @@ /*============================================================================= - + Library: CTK - + Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics - + 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 - + 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 CTKCMDLINEMODULEQTGUI_H -#define CTKCMDLINEMODULEQTGUI_H +#ifndef CTKCMDLINEMODULEFRONTENDQTGUI_H +#define CTKCMDLINEMODULEFRONTENDQTGUI_H -#include +#include -class ctkCmdLineModuleReference; +class QWidget; -class ctkCmdLineModuleQtGui : public ctkCmdLineModule +class ctkCmdLineModuleFrontendQtGui : public ctkCmdLineModuleFrontend { public: - ctkCmdLineModuleQtGui(const ctkCmdLineModuleReference& moduleRef); + ctkCmdLineModuleFrontendQtGui(const ctkCmdLineModuleReference& moduleRef); - // ctkCmdLineModule overrides + // ctkCmdLineModuleFrontend overrides virtual QObject* guiHandle() const; @@ -44,10 +44,10 @@ class ctkCmdLineModuleQtGui : public ctkCmdLineModule private: - mutable QWidget* WidgetTree; + mutable QWidget* Widget; // Cache the list of parameter names mutable QList ParameterNames; }; -#endif // CTKCMDLINEMODULEQTGUI_H +#endif // CTKCMDLINEMODULEFRONTENDQTGUI_H diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp similarity index 100% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h similarity index 96% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h index fb1b1d0a36..b73e267773 100644 --- a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h @@ -24,7 +24,7 @@ #include #include #include "ctkCmdLineModuleReference.h" -#include "ctkCommandLineModulesQtGuiExport.h" +#include "ctkCommandLineModulesFrontendQtGuiExport.h" /** * \class ctkCmdLineModuleMenuFactoryQtGui diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp similarity index 100% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp diff --git a/Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h similarity index 100% rename from Libs/CommandLineModules/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h rename to Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h diff --git a/Libs/CommandLineModules/QtGui/target_libraries.cmake b/Libs/CommandLineModules/Frontend/QtGui/target_libraries.cmake similarity index 100% rename from Libs/CommandLineModules/QtGui/target_libraries.cmake rename to Libs/CommandLineModules/Frontend/QtGui/target_libraries.cmake diff --git a/Libs/CommandLineModules/Testing/CMakeLists.txt b/Libs/CommandLineModules/Testing/CMakeLists.txt new file mode 100644 index 0000000000..ca3b9479ab --- /dev/null +++ b/Libs/CommandLineModules/Testing/CMakeLists.txt @@ -0,0 +1,5 @@ + +include_directories(${CTKCore_SOURCE_DIR} ${CTKCore_BINARY_DIR}) + +add_subdirectory(Modules) +add_subdirectory(Cpp) diff --git a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt new file mode 100644 index 0000000000..7e751e003d --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt @@ -0,0 +1,56 @@ +set(KIT CTKCommandLineModules) +set(LIBRARY_NAME ${KIT}) + +create_test_sourcelist(Tests ${KIT}CppTests.cpp + ctkCmdLineModuleFutureTest.cpp + ) + +set(TestsToRun ${Tests}) +remove(TestsToRun ${KIT}CppTests.cpp) + +set(Tests_SRCS ${Tests_SRCS} + ctkCmdLineModuleSignalTester.cpp +) +set(Tests_MOC_SRCS ${Tests_MOC_SRCS} + ctkCmdLineModuleSignalTester.h +) + +set(_base_src_include_dir ${CMAKE_SOURCE_DIR}/Libs/CommandLineModules) +set(_base_bin_include_dir ${CMAKE_BINARY_DIR}/Libs/CommandLineModules) + +include_directories( + ${CMAKE_SOURCE_DIR}/Libs/Testing + ${CMAKE_CURRENT_BINARY_DIR} + ${_base_src_include_dir}/Core + ${_base_bin_include_dir}/Core + ${_base_src_include_dir}/Backend/LocalProcess + ${_base_bin_include_dir}/Backend/LocalProcess + ) + +set(Tests_MOC_CPP) +QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) + +set(Tests_UI_CPP) +if(TEST_UI_FORMS) + QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) +endif() +set(Tests_RESOURCES_SRCS) +QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES}) + +add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS}) +target_link_libraries(${KIT}CppTests CTKCommandLineModulesBackendLocalProcess) +add_dependencies(${KIT}CppTests ctkCmdLineTestModules) + +if(TARGET CTKCommandLineModulesCoreCppTests) + add_dependencies(${KIT}CppTests CTKCommandLineModulesCoreCppTests) +endif() +if(TARGET CTKCommandLineModulesFrontendQtGuiCppTests) + add_dependencies(${KIT}CppTests CTKCommandLineModulesFrontendQtGuiCppTests) +endif() + +# +# Add Tests +# + +SIMPLE_TEST(ctkCmdLineModuleFutureTest) + diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp similarity index 71% rename from Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp rename to Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index 1cd7d3ce8c..41040df6af 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -20,8 +20,8 @@ =============================================================================*/ #include -#include -#include +#include +#include #include #include #include @@ -30,6 +30,8 @@ #include "ctkCmdLineModuleSignalTester.h" +#include "ctkCmdLineModuleBackendLocalProcess.h" + #include #include #include @@ -38,15 +40,16 @@ #include -class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleFactory +class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFactory { public: - virtual ctkCmdLineModule* create(const ctkCmdLineModuleReference& moduleRef) + virtual ctkCmdLineModuleFrontend* create(const ctkCmdLineModuleReference& moduleRef) { - struct ModuleTestInstance : public ctkCmdLineModule + struct ModuleFrontendMockup : public ctkCmdLineModuleFrontend { - ModuleTestInstance(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModule(moduleRef) {} + ModuleFrontendMockup(const ctkCmdLineModuleReference& moduleRef) + : ctkCmdLineModuleFrontend(moduleRef) {} virtual QObject* guiHandle() const { return NULL; } @@ -68,11 +71,14 @@ class ctkCmdLineModuleTestInstanceFactory : public ctkCmdLineModuleFactory QHash currentValues; }; - return new ModuleTestInstance(moduleRef); + return new ModuleFrontendMockup(moduleRef); } + + virtual QString name() const { return "Mock-up"; } + virtual QString description() const { return "A mock-up factory for testing."; } }; -bool futureTestStartFinish(ctkCmdLineModule* module) +bool futureTestStartFinish(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) { qDebug() << "Testing ctkCmdLineModuleFuture start/finish signals."; @@ -86,8 +92,7 @@ bool futureTestStartFinish(ctkCmdLineModule* module) QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - qDebug() << module->commandLineArguments(); - ctkCmdLineModuleFuture future = module->run(); + ctkCmdLineModuleFuture future = manager->run(frontend); watcher.setFuture(future); try @@ -106,7 +111,7 @@ bool futureTestStartFinish(ctkCmdLineModule* module) return signalTester.checkSignals(expectedSignals); } -bool futureTestProgress(ctkCmdLineModule* module) +bool futureTestProgress(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) { qDebug() << "Testing ctkCmdLineModuleFuture progress signals."; @@ -137,8 +142,8 @@ bool futureTestProgress(ctkCmdLineModule* module) QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString))); QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - module->setValue("numOutputsVar", 1); - ctkCmdLineModuleFuture future = module->run(); + frontend->setValue("numOutputsVar", 1); + ctkCmdLineModuleFuture future = manager->run(frontend); watcher.setFuture(future); try @@ -157,7 +162,7 @@ bool futureTestProgress(ctkCmdLineModule* module) return signalTester.checkSignals(expectedSignals); } -bool futureTestPauseAndCancel(ctkCmdLineModule* module) +bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) { qDebug() << "Testing ctkCmdLineModuleFuture pause and cancel capabilities"; @@ -171,9 +176,8 @@ bool futureTestPauseAndCancel(ctkCmdLineModule* module) QObject::connect(&watcher, SIGNAL(canceled()), &signalTester, SLOT(moduleCanceled())); QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - module->setValue("runtimeVar", 60); - qDebug() << module->commandLineArguments(); - ctkCmdLineModuleFuture future = module->run(); + frontend->setValue("runtimeVar", 60); + ctkCmdLineModuleFuture future = manager->run(frontend); watcher.setFuture(future); QList expectedSignals; @@ -213,6 +217,17 @@ bool futureTestPauseAndCancel(ctkCmdLineModule* module) future.togglePaused(); QCoreApplication::processEvents(); + sleep(1); + + if (future.isPaused() && future.isRunning()) + { + qDebug() << "Pause state wrong (module is paused, but it shouldn't be)"; + future.cancel(); + QCoreApplication::processEvents(); + future.waitForFinished(); + return false; + } + try { future.cancel(); @@ -241,16 +256,16 @@ bool futureTestPauseAndCancel(ctkCmdLineModule* module) return true; } -bool futureTestError(ctkCmdLineModule* module) +bool futureTestError(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) { qDebug() << "Testing ctkCmdLineModuleFuture error reporting."; - module->setValue("fileVar", "output1"); - module->setValue("exitCodeVar", 24); - module->setValue("errorTextVar", "Some error occured\n"); + frontend->setValue("fileVar", "output1"); + frontend->setValue("exitCodeVar", 24); + frontend->setValue("errorTextVar", "Some error occured\n"); QFutureWatcher watcher; - ctkCmdLineModuleFuture future = module->run(); + ctkCmdLineModuleFuture future = manager->run(frontend); watcher.setFuture(future); try @@ -274,49 +289,56 @@ int ctkCmdLineModuleFutureTest(int argc, char* argv[]) { QCoreApplication app(argc, argv); - ctkCmdLineModuleTestInstanceFactory factory; - ctkCmdLineModuleManager manager(&factory); + ctkCmdLineModuleFrontendMockupFactory factory; + ctkCmdLineModuleBackendLocalProcess backend; + + ctkCmdLineModuleManager manager; + manager.registerBackend(&backend); - QString moduleFilename = app.applicationDirPath() + "/ctkCmdLineModuleTestBed"; - ctkCmdLineModuleReference moduleRef = manager.registerModule(moduleFilename); - if (!moduleRef) + QUrl moduleUrl = QUrl::fromLocalFile(app.applicationDirPath() + "/ctkCmdLineModuleTestBed"); + ctkCmdLineModuleReference moduleRef; + try + { + moduleRef = manager.registerModule(moduleUrl); + } + catch (const ctkException& e) { - qCritical() << "Module at" << moduleFilename << "could not be registered"; + qCritical() << "Module at" << moduleUrl << "could not be registered: " << e; } { - QScopedPointer module(manager.createModule(moduleRef)); - if (!futureTestStartFinish(module.data())) + QScopedPointer frontend(factory.create(moduleRef)); + if (!futureTestStartFinish(&manager, frontend.data())) { return EXIT_FAILURE; } } { - QScopedPointer module(manager.createModule(moduleRef)); - if (!futureTestProgress(module.data())) + QScopedPointer frontend(factory.create(moduleRef)); + if (!futureTestProgress(&manager, frontend.data())) { return EXIT_FAILURE; } } { - QScopedPointer module(manager.createModule(moduleRef)); - if (!futureTestError(module.data())) + QScopedPointer frontend(factory.create(moduleRef)); + if (!futureTestError(&manager, frontend.data())) { return EXIT_FAILURE; } } { - QScopedPointer module(manager.createModule(moduleRef)); - if (!futureTestPauseAndCancel(module.data())) + QScopedPointer frontend(factory.create(moduleRef)); + if (!futureTestPauseAndCancel(&manager, frontend.data())) { return EXIT_FAILURE; } } - // if (!futureTestResultReady(module.data())) + // if (!futureTestResultReady(frontend.data())) // { // return EXIT_FAILURE; // } diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp new file mode 100644 index 0000000000..c8addc1ea0 --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp @@ -0,0 +1,116 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleSignalTester.h" + +#include + +void ctkCmdLineModuleSignalTester::moduleStarted() +{ + events.push_back("module.started"); +} + +void ctkCmdLineModuleSignalTester::moduleFinished() +{ + events.push_back("module.finished"); +} + +void ctkCmdLineModuleSignalTester::moduleProgressValueChanged(int /*progress*/) +{ + events.push_back("module.progressValueChanged"); +} + +void ctkCmdLineModuleSignalTester::moduleProgressTextChanged(const QString &/*text*/) +{ + events.push_back("module.progressTextChanged"); +} + +void ctkCmdLineModuleSignalTester::modulePaused() +{ + events.push_back("module.paused"); +} + +void ctkCmdLineModuleSignalTester::moduleResumed() +{ + events.push_back("module.resumed"); +} + +void ctkCmdLineModuleSignalTester::moduleCanceled() +{ + events.push_back("module.canceled"); +} + +void ctkCmdLineModuleSignalTester::filterStarted(const QString &/*name*/, const QString &/*comment*/) +{ + events.push_back("filter.started"); +} + +void ctkCmdLineModuleSignalTester::filterProgress(float /*progress*/) +{ + events.push_back("filter.progress"); +} + +void ctkCmdLineModuleSignalTester::filterFinished(const QString &/*name*/) +{ + events.push_back("filter.finished"); +} + +void ctkCmdLineModuleSignalTester::filterXmlError(const QString &/*error*/) +{ + events.push_back("filter.xmlError"); +} + +bool ctkCmdLineModuleSignalTester::checkSignals(const QList& expectedSignals) +{ + if (events.size() != expectedSignals.size()) + { + dumpSignals(expectedSignals); + return false; + } + + for (int i=0; i < expectedSignals.size(); ++i) + { + if (expectedSignals[i] != events[i]) + { + dumpSignals(expectedSignals); + return false; + } + } + return true; +} + +void ctkCmdLineModuleSignalTester::dumpSignals(const QList& expectedSignals) +{ + int max = events.size() > expectedSignals.size() ? events.size() : expectedSignals.size(); + qDebug() << "Expected signal -- Actual signal"; + for (int i = 0; i < max; ++i) + { + QString sig = i < events.size() ? events[i] : QString(); + if (i < expectedSignals.size()) + { + qDebug() << " " << expectedSignals[i] << "--" << sig; + } + else + { + qDebug() << " " << "- NONE - " << "--" << sig; + } + } +} diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h new file mode 100644 index 0000000000..eb3365c84c --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h @@ -0,0 +1,59 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULESIGNALTESTER_H +#define CTKCMDLINEMODULESIGNALTESTER_H + +#include +#include + +class ctkCmdLineModuleSignalTester : public QObject +{ + Q_OBJECT + +public: + + bool checkSignals(const QList& expectedSignals); + void dumpSignals(const QList& expectedSignals); + + +public Q_SLOTS: + + virtual void moduleStarted(); + virtual void moduleFinished(); + virtual void moduleProgressValueChanged(int progress); + virtual void moduleProgressTextChanged(const QString& text); + + virtual void modulePaused(); + virtual void moduleResumed(); + virtual void moduleCanceled(); + + virtual void filterStarted(const QString& name, const QString& comment); + virtual void filterProgress(float progress); + virtual void filterFinished(const QString& name); + virtual void filterXmlError(const QString& error); + +private: + + QList events; +}; + +#endif // CTKCMDLINEMODULESIGNALTESTER_H diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt b/Libs/CommandLineModules/Testing/Modules/Blur2dImage/CMakeLists.txt similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/CMakeLists.txt rename to Libs/CommandLineModules/Testing/Modules/Blur2dImage/CMakeLists.txt diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp b/Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp rename to Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.cpp diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc b/Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc rename to Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.qrc diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml b/Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml rename to Libs/CommandLineModules/Testing/Modules/Blur2dImage/ctkCmdLineModuleBlur2dImage.xml diff --git a/Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt b/Libs/CommandLineModules/Testing/Modules/CMakeLists.txt similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/CMakeLists.txt rename to Libs/CommandLineModules/Testing/Modules/CMakeLists.txt diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt b/Libs/CommandLineModules/Testing/Modules/TestBed/CMakeLists.txt similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/TestBed/CMakeLists.txt rename to Libs/CommandLineModules/Testing/Modules/TestBed/CMakeLists.txt diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp rename to Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc rename to Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.qrc diff --git a/Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml rename to Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt b/Libs/CommandLineModules/Testing/Modules/Tour/CMakeLists.txt similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Tour/CMakeLists.txt rename to Libs/CommandLineModules/Testing/Modules/Tour/CMakeLists.txt diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp b/Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp rename to Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.cpp diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc b/Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc rename to Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.qrc diff --git a/Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.xml b/Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.xml similarity index 100% rename from Libs/CommandLineModules/Core/Testing/Modules/Tour/ctkCmdLineModuleTour.xml rename to Libs/CommandLineModules/Testing/Modules/Tour/ctkCmdLineModuleTour.xml From cc4b2ed8a6fb8d075b1125270d25e43558ba7ba9 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Mon, 20 Aug 2012 17:16:52 +0200 Subject: [PATCH 118/247] Added experimental second front- (QtWebKit) and backend (function pointer). --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 11 + .../target_libraries.cmake | 2 + CMakeLists.txt | 5 + .../Backend/FunctionPointer/CMakeLists.txt | 67 ++++++ ...dLineModuleBackendFPDescriptionPrivate.cpp | 45 ++++ ...CmdLineModuleBackendFPDescriptionPrivate.h | 47 ++++ .../ctkCmdLineModuleBackendFPTypeTraits.h | 94 ++++++++ .../ctkCmdLineModuleBackendFPUtil.cpp | 60 +++++ .../ctkCmdLineModuleBackendFPUtil_p.h | 115 ++++++++++ ...ctkCmdLineModuleBackendFunctionPointer.cpp | 212 ++++++++++++++++++ .../ctkCmdLineModuleBackendFunctionPointer.h | 153 +++++++++++++ .../ctkCmdLineModuleFunctionPointerTask.cpp | 78 +++++++ .../ctkCmdLineModuleFunctionPointerTask_p.h | 47 ++++ .../FunctionPointer/target_libraries.cmake | 9 + .../Frontend/QtWebKit/CMakeLists.txt | 66 ++++++ .../ctkCmdLineModuleXmlToPlainHtml.xsl | 203 +++++++++++++++++ .../ctkCmdLineModulesFrontendQtWebKit.qrc | 5 + .../Frontend/QtWebKit/Resources/result.html | 78 +++++++ ...tkCmdLineModuleFrontendFactoryQtWebKit.cpp | 39 ++++ .../ctkCmdLineModuleFrontendFactoryQtWebKit.h | 41 ++++ .../ctkCmdLineModuleFrontendQtWebKit.cpp | 87 +++++++ .../ctkCmdLineModuleFrontendQtWebKit.h | 50 +++++ .../Frontend/QtWebKit/target_libraries.cmake | 9 + 23 files changed, 1523 insertions(+) create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/CMakeLists.txt create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.h create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h create mode 100644 Libs/CommandLineModules/Backend/FunctionPointer/target_libraries.cmake create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModuleXmlToPlainHtml.xsl create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModulesFrontendQtWebKit.qrc create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/Resources/result.html create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h create mode 100644 Libs/CommandLineModules/Frontend/QtWebKit/target_libraries.cmake diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index 623e72e45a..c4bf13eedc 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include #include @@ -48,12 +50,16 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : // Frontends moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtGui; + moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtWebKit; defaultModuleFrontendFactory = moduleFrontendFactories.front(); ui->modulesTreeWidget->setModuleFrontendFactories(moduleFrontendFactories); // Backends + ctkCmdLineModuleBackendFunctionPointer* backendFunctionPointer = new ctkCmdLineModuleBackendFunctionPointer; + moduleBackends.push_back(new ctkCmdLineModuleBackendLocalProcess); + moduleBackends.push_back(backendFunctionPointer); for(int i = 0; i < moduleBackends.size(); ++i) { moduleManager.registerBackend(moduleBackends[i]); @@ -85,6 +91,11 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : connect(¤tFutureWatcher, SIGNAL(canceled()), SLOT(currentModuleCanceled())); connect(¤tFutureWatcher, SIGNAL(finished()), SLOT(currentModuleFinished())); + foreach(QUrl fpModule, backendFunctionPointer->registeredFunctionPointers()) + { + moduleManager.registerModule(fpModule); + } + directoryWatcher.setDebug(true); directoryWatcher.setDirectories(QStringList(QCoreApplication::applicationDirPath())); diff --git a/Applications/ctkCommandLineModuleExplorer/target_libraries.cmake b/Applications/ctkCommandLineModuleExplorer/target_libraries.cmake index b35036bd3c..d00a0e283d 100644 --- a/Applications/ctkCommandLineModuleExplorer/target_libraries.cmake +++ b/Applications/ctkCommandLineModuleExplorer/target_libraries.cmake @@ -6,6 +6,8 @@ set(target_libraries CTKCommandLineModulesFrontendQtGui + CTKCommandLineModulesFrontendQtWebKit CTKCommandLineModulesBackendLocalProcess + CTKCommandLineModulesBackendFunctionPointer CTKWidgets ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c4395e334..7af560434f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -451,6 +451,9 @@ ctk_lib_option(Visualization/VTK/Widgets ctk_lib_option(CommandLineModules/Core "Build the Command Line Module core library" OFF) + +ctk_lib_option(CommandLineModules/Frontend/QtWebKit + "Build the QtWebKit based Command Line Module front-end" OFF) ctk_lib_option(CommandLineModules/Frontend/QtGui "Build the QtGui based Command Line Module front-end" OFF) @@ -458,6 +461,8 @@ ctk_lib_option(CommandLineModules/Frontend/QtGui ctk_lib_option(CommandLineModules/Backend/LocalProcess "Build the Command Line Module back-end for local processes" OFF) +ctk_lib_option(CommandLineModules/Backend/FunctionPointer + "Build the Command Line Module back-end for function pointers" OFF) #ctk_lib_option(Visualization/XIP # "Build the XIP library" OFF) diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/CMakeLists.txt b/Libs/CommandLineModules/Backend/FunctionPointer/CMakeLists.txt new file mode 100644 index 0000000000..c681404cef --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/CMakeLists.txt @@ -0,0 +1,67 @@ +project(CTKCommandLineModulesBackendFunctionPointer) + +# +# 3rd party dependencies +# + +# +# See CTK/CMake/ctkMacroBuildLib.cmake for details +# + +set(KIT_export_directive "CTK_CMDLINEMODULEBACKENDFP_EXPORT") + +# Additional directories to include + +# Source files +set(KIT_SRCS + ctkCmdLineModuleBackendFPTypeTraits.h + ctkCmdLineModuleBackendFPUtil.cpp + ctkCmdLineModuleBackendFPUtil_p.h + ctkCmdLineModuleBackendFunctionPointer.cpp + ctkCmdLineModuleBackendFPDescriptionPrivate.cpp + ctkCmdLineModuleFunctionPointerTask.cpp + ctkCmdLineModuleFunctionPointerTask_p.h +) + +# Headers that should run through moc +set(KIT_MOC_SRCS +) + +# UI files +set(KIT_UI_FORMS +) + +# Resources +set(KIT_resources +) + +# Target libraries - See CMake/ctkFunctionGetTargetLibraries.cmake +# The following macro will read the target libraries from the file 'target_libraries.cmake' +ctkFunctionGetTargetLibraries(KIT_target_libraries) + +ctkMacroBuildLib( + NAME ${PROJECT_NAME} + EXPORT_DIRECTIVE ${KIT_export_directive} + INCLUDE_DIRECTORIES ${KIT_include_directories} + SRCS ${KIT_SRCS} + MOC_SRCS ${KIT_MOC_SRCS} + UI_FORMS ${KIT_UI_FORMS} + TARGET_LIBRARIES ${KIT_target_libraries} + RESOURCES ${KIT_resources} + LIBRARY_TYPE ${CTK_LIBRARY_MODE} + ) + +target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) + +if(CTK_WRAP_PYTHONQT_FULL OR CTK_WRAP_PYTHONQT_LIGHT) + ctkMacroBuildLibWrapper( + TARGET ${PROJECT_NAME} + SRCS ${KIT_SRCS} + WRAPPER_LIBRARY_TYPE ${CTK_LIBRARY_MODE} + ) +endif() + +# Testing +if(BUILD_TESTING) + #add_subdirectory(Testing) +endif() diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp new file mode 100644 index 0000000000..9a0f59669e --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp @@ -0,0 +1,45 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleBackendFPDescriptionPrivate.h" + +QString ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate::xmlDescription() const +{ + QString xml; + QTextStream str(&xml); + str << "\n"; + str << "\n"; + str << " " + ModuleCategory + "\n"; + str << " " + ModuleTitle + "\n"; + str << " " + ModuleDescription + "\n"; + str << " " + ModuleContributor + "\n"; + str << " \n"; + str << " \n"; + str << " Parameters for calling a function pointer.\n"; + foreach (QString param, paramDescriptions) + { + str << param; + } + str << " \n"; + str << "\n"; + + return xml; +} diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.h new file mode 100644 index 0000000000..ce9fe0c178 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.h @@ -0,0 +1,47 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKENDFUNCTIONPOINTERDESCRIPTIONPRIVATE_H +#define CTKCMDLINEMODULEBACKENDFUNCTIONPOINTERDESCRIPTIONPRIVATE_H + +#include "ctkCmdLineModuleBackendFunctionPointer.h" + +#include "ctkCmdLineModuleBackendFPUtil_p.h" + +class ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate : public QSharedData +{ +public: + + QString xmlDescription() const; + + QUrl ModuleLocation; + QString ModuleCategory; + QString ModuleTitle; + QString ModuleDescription; + QString ModuleVersion; + QString ModuleContributor; + + ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy FpProxy; + + QList paramDescriptions; +}; + +#endif // CTKCMDLINEMODULEBACKENDFUNCTIONPOINTERDESCRIPTIONPRIVATE_H diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h new file mode 100644 index 0000000000..7f27f25256 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h @@ -0,0 +1,94 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKENDFPTYPETRAITS_H +#define CTKCMDLINEMODULEBACKENDFPTYPETRAITS_H + +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +struct NullType {}; + +template +struct Select +{ + typedef T Result; +}; + +template +struct Select +{ + typedef U Result; +}; + +template +class TypeTraits +{ +private: + + template struct PointerTraits + { + enum { result = false }; + typedef NullType PointeeType; + }; + template struct PointerTraits + { + enum { result = true }; + typedef U PointeeType; + }; + template struct ReferenceTraits + { + enum { result = false }; + typedef NullType ReferenceType; + }; + template struct ReferenceTraits + { + enum { result = true }; + typedef U ReferenceType; + }; + + template struct UnConst + { + typedef U Result; + }; + template struct UnConst + { + typedef U Result; + }; + +public: + + typedef typename PointerTraits::PointeeType PointeeType; + typedef typename ReferenceTraits::ReferenceType ReferenceType; + + enum { isPointer = PointerTraits::result }; + enum { isReference = ReferenceTraits::result }; + + typedef typename Select::Result, + typename Select::Result, typename UnConst::Result>::Result >::Result RawType; +}; + + +} +} + + +#endif // CTKCMDLINEMODULEBACKENDFPTYPETRAITS_H diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp new file mode 100644 index 0000000000..9941465175 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp @@ -0,0 +1,60 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleBackendFPUtil_p.h" + + +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +FunctionPointerHolderBase::~FunctionPointerHolderBase() +{ +} + + +FunctionPointerProxy::FunctionPointerProxy() + : FpHolder(NULL) +{} + +FunctionPointerProxy::~FunctionPointerProxy() +{ + delete FpHolder; +} + +FunctionPointerProxy::FunctionPointerProxy(const FunctionPointerProxy& other) + : FpHolder(other.FpHolder->clone()) +{ +} + +FunctionPointerProxy& FunctionPointerProxy::operator=(const FunctionPointerProxy& other) +{ + delete this->FpHolder; + this->FpHolder = other.FpHolder->clone(); + return *this; +} + +void FunctionPointerProxy::call(const QList &args) +{ + FpHolder->call(args); +} + +} +} diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h new file mode 100644 index 0000000000..c0e5fce717 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h @@ -0,0 +1,115 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKENDFPUTIL_P_H +#define CTKCMDLINEMODULEBACKENDFPUTIL_P_H + +#include + +class ctkCmdLineModuleBackendFunctionPointer; + +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +struct FunctionPointerHolderBase +{ + virtual ~FunctionPointerHolderBase(); + + virtual FunctionPointerHolderBase* clone() const = 0; + + virtual void call(const QList& args) = 0; +}; + + +template +struct FunctionPointerHolder : public FunctionPointerHolderBase +{ + typedef void (*FunctionPointerType)(A); + + FunctionPointerHolder(FunctionPointerType fp) : Fp(fp) {} + + FunctionPointerHolderBase* clone() const + { + return new FunctionPointerHolder(*this); + } + + void call(const QList& args) + { + Q_ASSERT(args.size() > 0); + Q_ASSERT(args.at(0).canConvert()); + Fp(args.at(0).value()); + } + + FunctionPointerType Fp; +}; + +template +struct FunctionPointerHolder2 : public FunctionPointerHolderBase +{ + typedef void (*FunctionPointerType)(A,B); + + FunctionPointerHolder2(FunctionPointerType fp) : Fp(fp) {} + + FunctionPointerHolderBase* clone() const + { + return new FunctionPointerHolder2(*this); + } + + void call(const QList& args) + { + Q_ASSERT(args.size() > 1); + Q_ASSERT(args.at(0).canConvert()); + Q_ASSERT(args.at(1).canConvert()); + Fp(args.at(0).value(), args.at(1).value()); + } + + FunctionPointerType Fp; +}; + +struct FunctionPointerProxy +{ + FunctionPointerProxy(); + ~FunctionPointerProxy(); + + FunctionPointerProxy(const FunctionPointerProxy& other); + FunctionPointerProxy& operator=(const FunctionPointerProxy& other); + + template + FunctionPointerProxy(void (*fp)(A)) + : FpHolder(new FunctionPointerHolder(fp)) {} + + template + FunctionPointerProxy(void (*fp)(A,B)) + : FpHolder(new FunctionPointerHolder2(fp)) {} + + void call(const QList& args); + +private: + + friend class ::ctkCmdLineModuleBackendFunctionPointer; + + FunctionPointerHolderBase* FpHolder; +}; + +} +} + +#endif // CTKCMDLINEMODULEBACKENDFPUTIL_P_H diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp new file mode 100644 index 0000000000..dc6707cdf5 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp @@ -0,0 +1,212 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleBackendFunctionPointer.h" + +#include "ctkCmdLineModuleBackendFPUtil_p.h" +#include "ctkCmdLineModuleBackendFPDescriptionPrivate.h" +#include "ctkCmdLineModuleFunctionPointerTask_p.h" + +#include "ctkCmdLineModuleFuture.h" +#include "ctkCmdLineModuleFrontend.h" + +#include +#include +#include +#include +#include + +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +template<> +CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName() +{ + return "integer"; +} + +template<> +CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName >() +{ + return "integer-vector"; +} + +} +} + +void CalculateFibonacciNumbers(int level) //, QList* result) +{ + qDebug() << "Number: 0"; + if (level > 0) + { + sleep(1); + qDebug() << "Number: 1"; + if (level == 1) return; + } + + int first = 0; + int second = 1; + for (int i = 1; i < level; ++i) + { + int tmp = first; + first = second; + second = first + tmp; + sleep(1); + qDebug() << "Number:" << second; + } +} + +ctkCmdLineModuleBackendFunctionPointer::Description::Description() + : d(new ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate) +{ +} + +ctkCmdLineModuleBackendFunctionPointer::Description::~Description() +{ +} + +QUrl ctkCmdLineModuleBackendFunctionPointer::Description::moduleLocation() const +{ + return d->ModuleLocation; +} + +QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleCategory() const +{ + return d->ModuleCategory; +} + +void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleCategory(const QString& category) +{ + d->ModuleCategory = category; +} + +QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleTitle() const +{ + return d->ModuleTitle; +} + +void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleTitle(const QString &title) +{ + d->ModuleTitle = title; +} + +QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleDescription() const +{ + return d->ModuleDescription; +} + +void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleDescription(const QString &description) +{ + d->ModuleDescription = description; +} + +QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleVersion() const +{ + return d->ModuleVersion; +} + +void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleVersion(const QString &version) +{ + d->ModuleVersion = version; +} + +QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleContributor() const +{ + return d->ModuleContributor; +} + +void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleContributor(const QString &contributor) +{ + d->ModuleContributor = contributor; +} + +ctkCmdLineModuleBackendFunctionPointer::Description::Description(const QUrl &location, + const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy &fpProxy) + : d(new ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate) +{ + d->ModuleLocation = location; + d->FpProxy = fpProxy; +} + +struct ctkCmdLineModuleBackendFunctionPointerPrivate +{ + QHash UrlToFpDescription; +}; + +ctkCmdLineModuleBackendFunctionPointer::ctkCmdLineModuleBackendFunctionPointer() + : d(new ctkCmdLineModuleBackendFunctionPointerPrivate) +{ + this->registerFunctionPointer("Fibonacci Number", CalculateFibonacciNumbers, "Count"); +} + +QString ctkCmdLineModuleBackendFunctionPointer::name() const +{ + return "Function Pointer (experimental)"; +} + +QString ctkCmdLineModuleBackendFunctionPointer::description() const +{ + return "Calls a previously registered function pointer."; +} + +QList ctkCmdLineModuleBackendFunctionPointer::schemes() const +{ + static QList supportedSchemes = QList() << "fp"; + return supportedSchemes; +} + +QByteArray ctkCmdLineModuleBackendFunctionPointer::rawXmlDescription(const QUrl& location) +{ + if (!d->UrlToFpDescription.contains(location)) return QByteArray(); + return QByteArray(qPrintable(d->UrlToFpDescription[location].d->xmlDescription())); +} + +ctkCmdLineModuleFuture ctkCmdLineModuleBackendFunctionPointer::run(ctkCmdLineModuleFrontend *frontend) +{ + QUrl url = frontend->location(); + + const Description& descr = d->UrlToFpDescription[url]; + QList args = frontend->values().values(); + + // Instances of ctkCmdLineModuleFunctionPointerTask are auto-deleted by the + // thread pool + ctkCmdLineModuleFunctionPointerTask* fpTask = new ctkCmdLineModuleFunctionPointerTask(descr, args); + return fpTask->start(); +} + +QList ctkCmdLineModuleBackendFunctionPointer::registeredFunctionPointers() const +{ + return d->UrlToFpDescription.keys(); +} + +ctkCmdLineModuleBackendFunctionPointer::Description* +ctkCmdLineModuleBackendFunctionPointer::registerFunctionPointerProxy(const QString& title, + const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy& proxy, + const QList& params) +{ + QUrl url(QString("fp://0x%1").arg(reinterpret_cast(proxy.FpHolder))); + d->UrlToFpDescription[url] = Description(url, proxy); + + Description& fpDescr = d->UrlToFpDescription[url]; + fpDescr.setModuleTitle(title); + fpDescr.d->paramDescriptions = params; + return &fpDescr; +} diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h new file mode 100644 index 0000000000..2d01191f8f --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h @@ -0,0 +1,153 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEBACKENDFUNCTIONPOINTER_H +#define CTKCMDLINEMODULEBACKENDFUNCTIONPOINTER_H + +#include "ctkCmdLineModuleBackend.h" + +#include "ctkCommandLineModulesBackendFunctionPointerExport.h" +#include "ctkCmdLineModuleBackendFPTypeTraits.h" + +#include +#include +#include +#include +#include + +#include + + +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +struct FunctionPointerProxy; + +template +QString GetParameterTypeName(); + +} +} + +Q_DECLARE_METATYPE(QList*) + +struct ctkCmdLineModuleBackendFunctionPointerPrivate; + +class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : public ctkCmdLineModuleBackend +{ + +public: + + class DescriptionPrivate; + + class Description + { + public: + + Description(); + ~Description(); + + QUrl moduleLocation() const; + + QString moduleCategory() const; + void setModuleCategory(const QString &category); + + QString moduleTitle() const; + void setModuleTitle(const QString& title); + + QString moduleDescription() const; + void setModuleDescription(const QString& description); + + QString moduleVersion() const; + void setModuleVersion(const QString& version); + + QString moduleContributor() const; + void setModuleContributor(const QString& contributor); + + private: + + friend class ctkCmdLineModuleBackendFunctionPointer; + friend class ctkCmdLineModuleFunctionPointerTask; + Description(const QUrl& location, const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy& fpProxy); + + QSharedPointer d; + + }; + + ctkCmdLineModuleBackendFunctionPointer(); + + virtual QString name() const; + virtual QString description() const; + + virtual QList schemes() const; + + virtual QByteArray rawXmlDescription(const QUrl& location); + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend); + + QList registeredFunctionPointers() const; + + template + Description* registerFunctionPointer(const QString& title, void (*fp)(A), + const QString& paramLabel = QString(), const QString& paramDescr = QString()) + { + QList params; + params << CreateXmlForParameter(0, paramLabel, paramDescr); + return this->registerFunctionPointerProxy(title, ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy(fp), params); + } + + template + Description* registerFunctionPointer(const QString& title, void (*fp)(A,B), + const QString& paramLabel0 = QString(), const QString& paramDescr0 = QString(), + const QString& paramLabel1 = QString(), const QString& paramDescr1 = QString()) + { + QList params; + params << CreateXmlForParameter(0, paramLabel0, paramDescr0); + params << CreateXmlForParameter(1, paramLabel1, paramDescr1); + return this->registerFunctionPointerProxy(title, ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy(fp), params); + } + +private: + + Description* registerFunctionPointerProxy(const QString &title, + const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy& proxy, + const QList& params); + + template + QString CreateXmlForParameter(int index, const QString& label = QString(), const QString& description = QString()) + { + QString xmlParameter; + QTextStream str(&xmlParameter); + QString typeName = ctk::CmdLineModuleBackendFunctionPointer::GetParameterTypeName::RawType>(); + str << " <" << typeName << ">\n"; + str << " " << QString("param%1").arg(index) << "\n"; + str << " " << index << "\n"; + str << " " << (description.isEmpty() ? "Description not available." : description) << "\n"; + str << " \n"; + str << " \n"; + return xmlParameter; + } + + QScopedPointer d; + +}; + +#endif // CTKCMDLINEMODULEBACKENDFUNCTIONPOINTER_H diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp new file mode 100644 index 0000000000..6af0352cc0 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp @@ -0,0 +1,78 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFunctionPointerTask_p.h" + +#include "ctkCmdLineModuleBackendFPDescriptionPrivate.h" + +#include "ctkCmdLineModuleFuture.h" +#include "ctkCmdLineModuleRunException.h" + +ctkCmdLineModuleFunctionPointerTask::ctkCmdLineModuleFunctionPointerTask(const ctkCmdLineModuleBackendFunctionPointer::Description &fpDescr, const QList ¶mValues) + : FpDescription(fpDescr) + , ParamValues(paramValues) +{ +} + +ctkCmdLineModuleFuture ctkCmdLineModuleFunctionPointerTask::start() +{ + this->setRunnable(this); + this->setProgressRange(0,0); + this->reportStarted(); + ctkCmdLineModuleFuture future = this->future(); + QThreadPool::globalInstance()->start(this, /*m_priority*/ 0); + return future; +} + +void ctkCmdLineModuleFunctionPointerTask::run() +{ + if (this->isCanceled()) + { + this->reportFinished(); + return; + } + + // call the function pointer and catch any exceptions + QString excMsg; + try + { + FpDescription.d->FpProxy.call(ParamValues); + } + catch (const std::exception& e) + { + excMsg = e.what(); + } + catch (...) + { + excMsg = "Unknown exception."; + } + + if (!excMsg.isNull()) + { + this->reportException(ctkCmdLineModuleRunException(FpDescription.moduleLocation(), 0, excMsg)); + } + + this->setProgressRange(0,1); + this->setProgressValue(1); + + //this->reportResult(result); + this->reportFinished(); +} diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h new file mode 100644 index 0000000000..2fb58dcf78 --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h @@ -0,0 +1,47 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFUNCTIONPOINTERTASK_P_H +#define CTKCMDLINEMODULEFUNCTIONPOINTERTASK_P_H + +#include "ctkCmdLineModuleFutureInterface.h" + +#include "ctkCmdLineModuleBackendFunctionPointer.h" + +#include + +class ctkCmdLineModuleFunctionPointerTask : public ctkCmdLineModuleFutureInterface, public QRunnable +{ +public: + + ctkCmdLineModuleFunctionPointerTask(const ctkCmdLineModuleBackendFunctionPointer::Description& fpDescr, const QList& paramValues); + + ctkCmdLineModuleFuture start(); + + void run(); + +private: + + ctkCmdLineModuleBackendFunctionPointer::Description FpDescription; + QList ParamValues; +}; + +#endif // CTKCMDLINEMODULEFUNCTIONPOINTERTASK_P_H diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/target_libraries.cmake b/Libs/CommandLineModules/Backend/FunctionPointer/target_libraries.cmake new file mode 100644 index 0000000000..139da8221c --- /dev/null +++ b/Libs/CommandLineModules/Backend/FunctionPointer/target_libraries.cmake @@ -0,0 +1,9 @@ +# +# See CMake/ctkMacroGetTargetLibraries.cmake +# +# This file should list the libraries required to build the current CTK libraries +# + +set(target_libraries + CTKCommandLineModulesCore + ) diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt new file mode 100644 index 0000000000..8da907bdfb --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt @@ -0,0 +1,66 @@ +project(CTKCommandLineModulesFrontendQtWebKit) + +# +# 3rd party dependencies +# + +# +# See CTK/CMake/ctkMacroBuildLib.cmake for details +# + +set(KIT_export_directive "CTK_CMDLINEMODULEQTWEBKIT_EXPORT") + +# Additional directories to include + +# Source files +set(KIT_SRCS + ctkCmdLineModuleFrontendFactoryQtWebKit.cpp + ctkCmdLineModuleFrontendQtWebKit.cpp +) + +# Headers that should run through moc +set(KIT_MOC_SRCS +) + +# UI files +set(KIT_UI_FORMS +) + +# Resources +set(KIT_resources + Resources/ctkCmdLineModulesFrontendQtWebKit.qrc +) + +set(QT_USE_QTWEBKIT 1) +include(${QT_USE_FILE}) + +# Target libraries - See CMake/ctkFunctionGetTargetLibraries.cmake +# The following macro will read the target libraries from the file 'target_libraries.cmake' +ctkFunctionGetTargetLibraries(KIT_target_libraries) + +ctkMacroBuildLib( + NAME ${PROJECT_NAME} + EXPORT_DIRECTIVE ${KIT_export_directive} + INCLUDE_DIRECTORIES ${KIT_include_directories} + SRCS ${KIT_SRCS} + MOC_SRCS ${KIT_MOC_SRCS} + UI_FORMS ${KIT_UI_FORMS} + TARGET_LIBRARIES ${KIT_target_libraries} + RESOURCES ${KIT_resources} + LIBRARY_TYPE ${CTK_LIBRARY_MODE} + ) + +target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) + +if(CTK_WRAP_PYTHONQT_FULL OR CTK_WRAP_PYTHONQT_LIGHT) + ctkMacroBuildLibWrapper( + TARGET ${PROJECT_NAME} + SRCS ${KIT_SRCS} + WRAPPER_LIBRARY_TYPE ${CTK_LIBRARY_MODE} + ) +endif() + +# Testing +if(BUILD_TESTING) +# add_subdirectory(Testing) +endif() diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModuleXmlToPlainHtml.xsl b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModuleXmlToPlainHtml.xsl new file mode 100644 index 0000000000..8e6dd60a8d --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModuleXmlToPlainHtml.xsl @@ -0,0 +1,203 @@ + + + + + + + + + + + + bool + number + double + string + + + + + + + + + checked + coordinates + currentPath + text + currentText + value + + + + + + + + + + + +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + <xsl:value-of select="title"/> + + +
+
+ + +
+
+ + +
+ + + + + +
+ + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModulesFrontendQtWebKit.qrc b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModulesFrontendQtWebKit.qrc new file mode 100644 index 0000000000..90c9ab63a4 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/ctkCmdLineModulesFrontendQtWebKit.qrc @@ -0,0 +1,5 @@ + + + ctkCmdLineModuleXmlToPlainHtml.xsl + + diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/Resources/result.html b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/result.html new file mode 100644 index 0000000000..0c80e72a4c --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/Resources/result.html @@ -0,0 +1,78 @@ + + + 2D Blurring + + +
+
+
+

Scalar Parameters

+ + + Variations on scalar parameters + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Integer Parameter + +
Boolean Parameter + +
Some file + +
Some dir + +
Some geom + +
Double Parameter + +
+
+
+

Vector Parameters

+ + Variations on vector parameters + + + + + + + + + + +
Float Vector Parameter + +
String Vector Parameter + +
+
+
+
+ + \ No newline at end of file diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp new file mode 100644 index 0000000000..eb47772507 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp @@ -0,0 +1,39 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFrontendFactoryQtWebKit.h" + + +ctkCmdLineModuleFrontendQtWebKit *ctkCmdLineModuleFrontendFactoryQtWebKit::create(const ctkCmdLineModuleReference &moduleRef) +{ + return new ctkCmdLineModuleFrontendQtWebKit(moduleRef); +} + + +QString ctkCmdLineModuleFrontendFactoryQtWebKit::name() const +{ + return "Qt WebKit (experimental)"; +} + +QString ctkCmdLineModuleFrontendFactoryQtWebKit::description() const +{ + return "An experimental frontend using the QtWebKit library."; +} diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h new file mode 100644 index 0000000000..648a7220ec --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h @@ -0,0 +1,41 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFRONTENDFACTORYQTWEBKIT_H +#define CTKCMDLINEMODULEFRONTENDFACTORYQTWEBKIT_H + +#include "ctkCommandLineModulesFrontendQtWebKitExport.h" + +#include "ctkCmdLineModuleFrontendFactory.h" +#include "ctkCmdLineModuleFrontendQtWebKit.h" + +class CTK_CMDLINEMODULEQTWEBKIT_EXPORT ctkCmdLineModuleFrontendFactoryQtWebKit : public ctkCmdLineModuleFrontendFactory +{ + +public: + + virtual QString name() const; + virtual QString description() const; + + virtual ctkCmdLineModuleFrontendQtWebKit* create(const ctkCmdLineModuleReference& moduleRef); +}; + +#endif // CTKCMDLINEMODULEFRONTENDFACTORYQTWEBKIT_H diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp new file mode 100644 index 0000000000..e7a0cdf52a --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp @@ -0,0 +1,87 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFrontendQtWebKit.h" + +#include "ctkCmdLineModuleXslTransform.h" +#include "ctkCmdLineModuleReference.h" + +#include +#include +#include +#include +#include + +#include + +ctkCmdLineModuleFrontendQtWebKit::ctkCmdLineModuleFrontendQtWebKit(const ctkCmdLineModuleReference& moduleRef) + : ctkCmdLineModuleFrontend(moduleRef) + , WebView(NULL) +{ + +} + +QObject* ctkCmdLineModuleFrontendQtWebKit::guiHandle() const +{ + if (WebView) return WebView; + + QBuffer input; + input.setData(moduleReference().rawXmlDescription()); + + QBuffer htmlOutput; + htmlOutput.open(QIODevice::ReadWrite); + ctkCmdLineModuleXslTransform xslTransform(&input, &htmlOutput); + QFile htmlTransformation(":/ctkCmdLineModuleXmlToPlainHtml.xsl"); + + xslTransform.setXslTransformation(&htmlTransformation); + if (!xslTransform.transform()) + { + // maybe throw an exception + qCritical() << xslTransform.errorString(); + return 0; + } + + this->WebView = new QWebView; + QByteArray htmlContent = htmlOutput.readAll(); + this->WebView->setHtml(htmlContent); + return this->WebView; +} + +QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter) const +{ + QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]"); + if (webElement.isNull()) return QVariant(); + // Work around bug https://bugs.webkit.org/show_bug.cgi?id=32865 for input elements + QVariant value = webElement.evaluateJavaScript("this.value"); + qDebug() << "Found element" << webElement.tagName() << "with value" << value; + return value; +} + +void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString ¶meter, const QVariant &value) +{ + if (!this->WebView) return; + + QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]"); + if (webElement.isNull()) return; + + // Work around bug https://bugs.webkit.org/show_bug.cgi?id=32865 for input elements + webElement.evaluateJavaScript(QString("this.value='%1'").arg(value.toString())); +} diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h new file mode 100644 index 0000000000..5e9fbbe683 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h @@ -0,0 +1,50 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFRONTENDQTWEBKIT_H +#define CTKCMDLINEMODULEFRONTENDQTWEBKIT_H + +#include "ctkCmdLineModuleFrontend.h" + +class QWebView; + +class ctkCmdLineModuleFrontendQtWebKit : public ctkCmdLineModuleFrontend +{ + +public: + + ctkCmdLineModuleFrontendQtWebKit(const ctkCmdLineModuleReference& moduleRef); + + // ctkCmdLineModuleFrontend overrides + + virtual QObject* guiHandle() const; + + virtual QVariant value(const QString& parameter) const; + virtual void setValue(const QString& parameter, const QVariant& value); + + //virtual QList parameterNames() const; + +private: + + mutable QWebView* WebView; +}; + +#endif // CTKCMDLINEMODULEFRONTENDQTWEBKIT_H diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/target_libraries.cmake b/Libs/CommandLineModules/Frontend/QtWebKit/target_libraries.cmake new file mode 100644 index 0000000000..2eea359f6d --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtWebKit/target_libraries.cmake @@ -0,0 +1,9 @@ +# +# See CMake/ctkMacroGetTargetLibraries.cmake +# +# This file should list the libraries required to build the current CTK libraries +# + +set(target_libraries + CTKCommandLineModulesCore +) From 004e94714171a9d0cc248b657fbfeb3889877963 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Mon, 20 Aug 2012 19:34:50 +0200 Subject: [PATCH 119/247] The ctkCmdLineModuleManager is now thread-safe. The directory watcher now concurrently adds new modules to the manager. --- .../Core/ctkCmdLineModuleBackend.h | 9 ++ .../Core/ctkCmdLineModuleDirectoryWatcher.cpp | 119 +++++++++++++----- .../Core/ctkCmdLineModuleDirectoryWatcher_p.h | 12 +- .../Core/ctkCmdLineModuleManager.cpp | 54 ++++++-- 4 files changed, 150 insertions(+), 44 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h index 7b906e0604..44f3b8217c 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h @@ -40,6 +40,15 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend virtual QList schemes() const = 0; + /** + * @brief Get the XML parameter description from the given location. + * @param location The location URL specifying the module. + * @return The raw XML parameter description. + * + * This method may be concurrently called by the ctkCmdLineModuleManager and + * must be thread-safe. + * + */ virtual QByteArray rawXmlDescription(const QUrl& location) = 0; protected: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp index 2e22df9387..ddd1a7a3b5 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp @@ -30,9 +30,77 @@ #include #include #include +#include #include +//----------------------------------------------------------------------------- +// A function object for concurrently adding modules +namespace { +struct AddModule +{ + typedef ctkCmdLineModuleReference result_type; + + AddModule(ctkCmdLineModuleManager* manager, bool debug = false) + : ModuleManager(manager), Debug(debug) + {} + + ctkCmdLineModuleReference operator()(const QString& moduleLocation) + { + try + { + return this->ModuleManager->registerModule(QUrl::fromLocalFile(moduleLocation)); + } + catch (const ctkException& e) + { + if (this->Debug) + { + qDebug() << e; + } + return ctkCmdLineModuleReference(); + } + catch (...) + { + if (this->Debug) + { + qDebug() << "Registering module" << moduleLocation << "failed with an unknown exception."; + } + return ctkCmdLineModuleReference(); + } + } + + ctkCmdLineModuleManager* ModuleManager; + bool Debug; +}; +} + +//----------------------------------------------------------------------------- +// A function object for concurrently removing modules +namespace { +struct RemoveModule +{ + typedef bool result_type; + + RemoveModule(ctkCmdLineModuleManager* manager) + : ModuleManager(manager) + {} + + bool operator()(const QString& moduleLocation) + { + ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(QUrl::fromLocalFile(moduleLocation)); + if (ref) + { + this->ModuleManager->unregisterModule(ref); + return true; + } + return false; + } + + ctkCmdLineModuleManager* ModuleManager; +}; +} + + //----------------------------------------------------------------------------- // ctkCmdLineModuleDirectoryWatcher methods @@ -240,6 +308,9 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringL QString path; QStringList currentlyWatchedDirectories = this->directories(); + QStringList modulesToUnload; + QStringList modulesToLoad; + // First remove modules from current directories that are no longer in the requested "directories" list. foreach (path, currentlyWatchedDirectories) { @@ -250,7 +321,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringL QString filename; foreach (filename, currentlyWatchedFiles) { - this->unloadModule(filename); + modulesToUnload << filename; } } } @@ -269,7 +340,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringL { if (!executablesInDirectory.contains(executable)) { - this->unloadModule(executable); + modulesToUnload << executable; } } @@ -277,7 +348,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringL { if (!currentlyWatchedFiles.contains(executable)) { - this->loadModule(executable); + modulesToLoad << executable; } } } @@ -289,10 +360,13 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::setModuleReferences(const QStringL QString executable; foreach (executable, executables) { - this->loadModule(executable); + modulesToLoad << executable; } } } + + this->unloadModules(modulesToUnload); + this->loadModules(modulesToLoad); } @@ -312,41 +386,28 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateModuleReferences(const QStri //----------------------------------------------------------------------------- -ctkCmdLineModuleReference ctkCmdLineModuleDirectoryWatcherPrivate::loadModule(const QString& pathToExecutable) +QList ctkCmdLineModuleDirectoryWatcherPrivate::loadModules(const QStringList& executables) { - ctkCmdLineModuleReference ref; - try - { - ref = this->ModuleManager->registerModule(QUrl::fromLocalFile(pathToExecutable)); - } - catch (const ctkIllegalStateException& e) - { - e.rethrow(); - } - catch (const ctkException& e) + QList refs = QtConcurrent::blockingMapped(executables, AddModule(this->ModuleManager, this->Debug)); + + for (int i = 0; i < executables.size(); ++i) { - if (this->Debug) + if (refs[i]) { - qWarning() << e; + this->MapFileNameToReference[executables[i]] = refs[i]; } } - - if (ref) - { - this->MapFileNameToReference[pathToExecutable] = ref; - } - return ref; + return refs; } //----------------------------------------------------------------------------- -void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModule(const QString& pathToExecutable) +void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModules(const QStringList& executables) { - ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(QUrl::fromLocalFile(pathToExecutable)); - if (ref) + QtConcurrent::blockingMapped(executables, RemoveModule(this->ModuleManager)); + foreach(QString executable, executables) { - this->ModuleManager->unregisterModule(ref); - this->MapFileNameToReference.remove(pathToExecutable); + this->MapFileNameToReference.remove(executable); } } @@ -354,7 +415,7 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModule(const QString& pathTo //----------------------------------------------------------------------------- void ctkCmdLineModuleDirectoryWatcherPrivate::onFileChanged(const QString& path) { - ctkCmdLineModuleReference ref = this->loadModule(path); + ctkCmdLineModuleReference ref = this->loadModules(QStringList() << path).front(); if (ref) { if (this->Debug) qDebug() << "Reloaded " << path; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h index 1c1f7456dd..ffbe579d6b 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h @@ -124,17 +124,17 @@ public Q_SLOTS: void updateModuleReferences(const QString &directory); /** - * \brief Uses the ctkCmdLineModuleManager to try and add the executable to the list + * \brief Uses the ctkCmdLineModuleManager to try and add the executables to the list * of executables, and if successful it is added to this->MapFileNameToReference. - * \param pathToExecutable path to an executable file, denoted by its absolute path. + * \param executables A list of paths to executable files, denoted by an absolute path. */ - ctkCmdLineModuleReference loadModule(const QString& pathToExecutable); + QList loadModules(const QStringList& executables); /** - * \brief Removes the executable from both the ctkCmdLineModuleManager and this->MapFileNameToReference. - * \param pathToExecutable path to an executable file, denoted by its absolute path. + * \brief Removes the executables from both the ctkCmdLineModuleManager and this->MapFileNameToReference. + * \param executables path to an executable file, denoted by its absolute path. */ - void unloadModule(const QString& pathToExecutable); + void unloadModules(const QStringList& executables); QHash MapFileNameToReference; ctkCmdLineModuleManager* ModuleManager; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 11ca3e96e8..90ac0ee668 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -44,7 +45,7 @@ struct ctkCmdLineModuleManagerPrivate : ValidationMode(mode) {} - void checkBackends(const QUrl& location) + void checkBackends_unlocked(const QUrl& location) { if (!this->SchemeToBackend.contains(location.scheme())) { @@ -52,10 +53,11 @@ struct ctkCmdLineModuleManagerPrivate } } + QMutex Mutex; QHash SchemeToBackend; QHash LocationToRef; - ctkCmdLineModuleManager::ValidationMode ValidationMode; + const ctkCmdLineModuleManager::ValidationMode ValidationMode; }; ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode) @@ -69,9 +71,11 @@ ctkCmdLineModuleManager::~ctkCmdLineModuleManager() void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend) { + QMutexLocker lock(&d->Mutex); + QList supportedSchemes = backend->schemes(); - // Check if there is already a backound registerd for any of the + // Check if there is already a backend registerd for any of the // supported schemes. We only supported one backend per scheme. foreach (QString scheme, supportedSchemes) { @@ -91,10 +95,23 @@ void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend) ctkCmdLineModuleReference ctkCmdLineModuleManager::registerModule(const QUrl &location) { - d->checkBackends(location); + QByteArray xml; + ctkCmdLineModuleBackend* backend = NULL; + { + QMutexLocker lock(&d->Mutex); + + d->checkBackends_unlocked(location); + + // If the module is already registered, just return the reference + if (d->LocationToRef.contains(location)) + { + return d->LocationToRef[location]; + } - QByteArray xml = d->SchemeToBackend[location.scheme()]->rawXmlDescription(location); + backend = d->SchemeToBackend[location.scheme()]; + } + xml = backend->rawXmlDescription(location); if (xml.isEmpty()) { throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString()); @@ -103,7 +120,7 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) ctkCmdLineModuleReference ref; ref.d->Location = location; ref.d->RawXmlDescription = xml; - ref.d->Backend = d->SchemeToBackend[location.scheme()]; + ref.d->Backend = backend; if (d->ValidationMode != SKIP_VALIDATION) { @@ -126,7 +143,16 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) } } - d->LocationToRef[location] = ref; + { + QMutexLocker lock(&d->Mutex); + // Check that we don't have a race condition + if (d->LocationToRef.contains(location)) + { + // Another thread registered a module with the same location + return d->LocationToRef[location]; + } + d->LocationToRef[location] = ref; + } emit moduleRegistered(ref); return ref; @@ -134,23 +160,33 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref) { - d->LocationToRef.remove(ref.location()); + { + QMutexLocker lock(&d->Mutex); + if (!d->LocationToRef.contains(ref.location())) + { + return; + } + d->LocationToRef.remove(ref.location()); + } emit moduleUnregistered(ref); } ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const { + QMutexLocker lock(&d->Mutex); return d->LocationToRef[location]; } QList ctkCmdLineModuleManager::moduleReferences() const { + QMutexLocker lock(&d->Mutex); return d->LocationToRef.values(); } ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend) { - d->checkBackends(frontend->location()); + QMutexLocker lock(&d->Mutex); + d->checkBackends_unlocked(frontend->location()); ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend); frontend->setFuture(future); From b843ce6b627300070f96180d86498de4c8d366f6 Mon Sep 17 00:00:00 2001 From: Julien Finet Date: Mon, 20 Aug 2012 16:03:34 -0400 Subject: [PATCH 120/247] Cleanup ctkColorDialogTest1 and ctkColorDialogTest2 Closes #210 --- Libs/Widgets/Testing/Cpp/ctkColorDialogTest1.cpp | 5 ----- Libs/Widgets/Testing/Cpp/ctkColorDialogTest2.cpp | 9 ++++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Libs/Widgets/Testing/Cpp/ctkColorDialogTest1.cpp b/Libs/Widgets/Testing/Cpp/ctkColorDialogTest1.cpp index cfc3e76f46..9a532371a1 100644 --- a/Libs/Widgets/Testing/Cpp/ctkColorDialogTest1.cpp +++ b/Libs/Widgets/Testing/Cpp/ctkColorDialogTest1.cpp @@ -93,9 +93,4 @@ int ctkColorDialogTest1(int argc, char * argv [] ) } return app.exec(); - - ctkColorDialog::addDefaultTab(extraPanel, "Extra"); - QColor color = ctkColorDialog::getColor(Qt::black,0 , "", 0); - return EXIT_SUCCESS; - } diff --git a/Libs/Widgets/Testing/Cpp/ctkColorDialogTest2.cpp b/Libs/Widgets/Testing/Cpp/ctkColorDialogTest2.cpp index 885b25f650..dfcee1c6c4 100644 --- a/Libs/Widgets/Testing/Cpp/ctkColorDialogTest2.cpp +++ b/Libs/Widgets/Testing/Cpp/ctkColorDialogTest2.cpp @@ -46,9 +46,12 @@ int ctkColorDialogTest2(int argc, char * argv [] ) QTimer::singleShot(300, &app, SLOT(quit())); } - // The opened dialog blocks QTimers which prevents the test - // from being quit. QColor color = ctkColorDialog::getColor(Qt::black,0 , "", QColorDialog::DontUseNativeDialog); - + if (color.isValid()) + { + std::cout << "The color dialog should have been quit without a valid color." + << std::endl; + return EXIT_FAILURE; + } return app.exec(); } From 9129b3ab17b900109a818341ebb8e228e598967b Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Mon, 20 Aug 2012 23:54:57 +0200 Subject: [PATCH 121/247] Added caching support cmd line module xml descriptions. --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 3 +- .../ctkCommandLineModuleExplorerMain.cpp | 2 + ...ctkCmdLineModuleBackendFunctionPointer.cpp | 6 + .../ctkCmdLineModuleBackendFunctionPointer.h | 2 + .../ctkCmdLineModuleBackendLocalProcess.cpp | 13 ++ .../ctkCmdLineModuleBackendLocalProcess.h | 2 + Libs/CommandLineModules/Core/CMakeLists.txt | 2 + .../Core/ctkCmdLineModuleBackend.h | 2 + .../Core/ctkCmdLineModuleCache.cpp | 174 ++++++++++++++++++ .../Core/ctkCmdLineModuleCache_p.h | 53 ++++++ .../Core/ctkCmdLineModuleManager.cpp | 93 +++++++++- .../Core/ctkCmdLineModuleManager.h | 2 +- 12 files changed, 347 insertions(+), 7 deletions(-) create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleCache.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index c4bf13eedc..635e2241eb 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -36,14 +36,15 @@ #include +#include #include ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::ctkCmdLineModuleExplorerMainWindow), - tabList(NULL), defaultModuleFrontendFactory(NULL), + moduleManager(ctkCmdLineModuleManager::STRICT_VALIDATION, QDesktopServices::storageLocation(QDesktopServices::CacheLocation)), directoryWatcher(&moduleManager) { ui->setupUi(this); diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp index 0d2391483b..5a263a85d6 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCommandLineModuleExplorerMain.cpp @@ -41,6 +41,8 @@ int main(int argc, char** argv) { QApplication myApp(argc, argv); + myApp.setOrganizationName("CommonTK"); + myApp.setApplicationName("CommandLineModuleExplorer"); ctkCommandLineParser cmdLineParser; cmdLineParser.setArgumentPrefix("--", "-"); diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp index dc6707cdf5..3c53d969c0 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp @@ -173,6 +173,12 @@ QList ctkCmdLineModuleBackendFunctionPointer::schemes() const return supportedSchemes; } +qint64 ctkCmdLineModuleBackendFunctionPointer::timeStamp(const QUrl &location) const +{ + Q_UNUSED(location) + return 0; +} + QByteArray ctkCmdLineModuleBackendFunctionPointer::rawXmlDescription(const QUrl& location) { if (!d->UrlToFpDescription.contains(location)) return QByteArray(); diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h index 2d01191f8f..38e05e7a2c 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h @@ -99,6 +99,8 @@ class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : virtual QList schemes() const; + virtual qint64 timeStamp(const QUrl &location) const; + virtual QByteArray rawXmlDescription(const QUrl& location); virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend); diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp index f176ce0094..9d8b469a59 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp @@ -30,6 +30,8 @@ #include "ctkCmdLineModuleReference.h" #include "ctkCmdLineModuleRunException.h" +#include "ctkUtils.h" + #include #include @@ -126,6 +128,17 @@ QList ctkCmdLineModuleBackendLocalProcess::schemes() const return supportedSchemes; } +qint64 ctkCmdLineModuleBackendLocalProcess::timeStamp(const QUrl &location) const +{ + QFileInfo fileInfo(location.toLocalFile()); + if (fileInfo.exists()) + { + QDateTime dateTime = fileInfo.lastModified(); + return ctk::msecsTo(QDateTime::fromTime_t(0), dateTime); + } + return 0; +} + QByteArray ctkCmdLineModuleBackendLocalProcess::rawXmlDescription(const QUrl &location) { QProcess process; diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h index 101433ebfa..11c88dcaac 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h @@ -43,6 +43,8 @@ class CTK_CMDLINEMODULEBACKENDLP_EXPORT ctkCmdLineModuleBackendLocalProcess : pu virtual QList schemes() const; + virtual qint64 timeStamp(const QUrl &location) const; + virtual QByteArray rawXmlDescription(const QUrl& location); virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend); diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 98cf01fd1e..e9327a0e40 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -15,6 +15,8 @@ set(KIT_export_directive "CTK_CMDLINEMODULECORE_EXPORT") # Source files set(KIT_SRCS ctkCmdLineModuleBackend.cpp + ctkCmdLineModuleCache.cpp + ctkCmdLineModuleCache_p.h ctkCmdLineModuleDefaultPathBuilder.cpp ctkCmdLineModuleDescription.cpp ctkCmdLineModuleDescription_p.h diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h index 44f3b8217c..e00d4448db 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h @@ -40,6 +40,8 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend virtual QList schemes() const = 0; + virtual qint64 timeStamp(const QUrl& location) const = 0; + /** * @brief Get the XML parameter description from the given location. * @param location The location URL specifying the module. diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache.cpp new file mode 100644 index 0000000000..1cfe6858d6 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache.cpp @@ -0,0 +1,174 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleCache_p.h" + +#include +#include +#include +#include +#include + +struct ctkCmdLineModuleCachePrivate +{ + QString CacheDir; + + QHash LocationToTimeStamp; + QHash LocationToXmlDescription; + + QMutex Mutex; + + void LoadTimeStamps() + { + QDirIterator dirIter(this->CacheDir, QStringList() << "*.timestamp", QDir::Files | QDir::Readable); + while(dirIter.hasNext()) + { + QFile timestampFile(dirIter.next()); + timestampFile.open(QIODevice::ReadOnly); + QUrl url = QUrl(timestampFile.readLine().trimmed().data()); + QByteArray timestamp = timestampFile.readLine(); + bool ok = false; + qint64 ts = timestamp.toLongLong(&ok); + if (ok && !url.isEmpty()) + { + this->LocationToTimeStamp[url] = ts; + } + } + } + + QString timeStampFileName(const QUrl& moduleLocation) const + { + return this->CacheDir + "/" + QString::number(qHash(moduleLocation)) + ".timestamp"; + } + + QString xmlFileName(const QUrl& moduleLocation) const + { + return this->CacheDir + "/" + QString::number(qHash(moduleLocation)) + ".xml"; + } +}; + +ctkCmdLineModuleCache::ctkCmdLineModuleCache(const QString& cacheDir) + : d(new ctkCmdLineModuleCachePrivate) +{ + d->CacheDir = cacheDir; + d->LoadTimeStamps(); +} + +ctkCmdLineModuleCache::~ctkCmdLineModuleCache() +{ +} + +QString ctkCmdLineModuleCache::cacheDir() const +{ + QMutexLocker lock(&d->Mutex); + return d->CacheDir; +} + +QByteArray ctkCmdLineModuleCache::rawXmlDescription(const QUrl& moduleLocation) const +{ + QMutexLocker lock(&d->Mutex); + + if (d->LocationToXmlDescription.contains(moduleLocation)) + { + return d->LocationToXmlDescription[moduleLocation]; + } + // lazily load the XML description from the file system + QByteArray xml; + QString a = moduleLocation.toString(); + QString fn = d->xmlFileName(moduleLocation); + QFile xmlFile(d->xmlFileName(moduleLocation)); + if (xmlFile.exists() && xmlFile.open(QIODevice::ReadOnly)) + { + xml = xmlFile.readAll(); + xmlFile.close(); + } + d->LocationToXmlDescription[moduleLocation] = xml; + return xml; +} + +qint64 ctkCmdLineModuleCache::timeStamp(const QUrl& moduleLocation) const +{ + QMutexLocker lock(&d->Mutex); + if (d->LocationToTimeStamp.contains(moduleLocation)) + { + return d->LocationToTimeStamp[moduleLocation]; + } + return -1; +} + +void ctkCmdLineModuleCache::cacheXmlDescription(const QUrl& moduleLocation, qint64 timestamp, const QByteArray& xmlDescription) +{ + QFile timestampFile(d->timeStampFileName(moduleLocation)); + QFile xmlFile(d->xmlFileName(moduleLocation)); + timestampFile.remove(); + timestampFile.open(QIODevice::WriteOnly); + + QByteArray ba; + QTextStream str(&ba); + str << moduleLocation.toString() << '\n' << timestamp; + str.flush(); + if (timestampFile.write(ba) == -1) + { + timestampFile.close(); + timestampFile.remove(); + return; + } + timestampFile.close(); + + xmlFile.remove(); + if (!xmlDescription.isEmpty()) + { + xmlFile.open(QIODevice::WriteOnly); + if (xmlFile.write(xmlDescription) == -1) + { + timestampFile.remove(); + xmlFile.close(); + xmlFile.remove(); + return; + } + } + + { + QMutexLocker lock(&d->Mutex); + d->LocationToXmlDescription[moduleLocation] = xmlDescription; + d->LocationToTimeStamp[moduleLocation] = timestamp; + } +} + +void ctkCmdLineModuleCache::removeCacheEntry(const QUrl& moduleLocation) +{ + { + QMutexLocker lock(&d->Mutex); + d->LocationToTimeStamp.remove(moduleLocation); + d->LocationToXmlDescription.remove(moduleLocation); + } + + QFile timestampFile(d->timeStampFileName(moduleLocation)); + if (timestampFile.exists()) + { + timestampFile.remove(); + } + QFile xmlFile(d->xmlFileName(moduleLocation)); + if (xmlFile.exists()) + { + xmlFile.remove(); + } +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h new file mode 100644 index 0000000000..84c1f0fd6f --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h @@ -0,0 +1,53 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULECACHE_H +#define CTKCMDLINEMODULECACHE_H + +#include + +class ctkCmdLineModuleCachePrivate; + +class QUrl; + +class ctkCmdLineModuleCache +{ + +public: + + ctkCmdLineModuleCache(const QString& cacheDir); + ~ctkCmdLineModuleCache(); + + QString cacheDir() const; + + QByteArray rawXmlDescription(const QUrl& moduleLocation) const; + qint64 timeStamp(const QUrl& moduleLocation) const; + + void cacheXmlDescription(const QUrl& moduleLocation, qint64 timestamp, const QByteArray& xmlDescription); + + void removeCacheEntry(const QUrl& moduleLocation); + +private: + + QScopedPointer d; +}; + +#endif // CTKCMDLINEMODULECACHE_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 90ac0ee668..2cb84f85c6 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -23,6 +23,7 @@ #include "ctkCmdLineModuleBackend.h" #include "ctkCmdLineModuleFrontend.h" +#include "ctkCmdLineModuleCache_p.h" #include "ctkCmdLineModuleFuture.h" #include "ctkCmdLineModuleXmlValidator.h" #include "ctkCmdLineModuleReference.h" @@ -30,6 +31,8 @@ #include +#include +#include #include #include #include @@ -41,9 +44,28 @@ struct ctkCmdLineModuleManagerPrivate { - ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode) + ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir) : ValidationMode(mode) - {} + { + QFileInfo fileInfo(cacheDir); + if (!fileInfo.exists()) + { + if (!QDir().mkpath(cacheDir)) + { + qWarning() << "Command line module cache disabled. Directory" << cacheDir << "could not be created."; + return; + } + } + + if (fileInfo.isWritable()) + { + ModuleCache.reset(new ctkCmdLineModuleCache(cacheDir)); + } + else + { + qWarning() << "Command line module cache disabled. Directory" << cacheDir << "is not writable."; + } + } void checkBackends_unlocked(const QUrl& location) { @@ -56,12 +78,13 @@ struct ctkCmdLineModuleManagerPrivate QMutex Mutex; QHash SchemeToBackend; QHash LocationToRef; + QScopedPointer ModuleCache; const ctkCmdLineModuleManager::ValidationMode ValidationMode; }; -ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode) - : d(new ctkCmdLineModuleManagerPrivate(validationMode)) +ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir) + : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir)) { } @@ -111,9 +134,43 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) backend = d->SchemeToBackend[location.scheme()]; } - xml = backend->rawXmlDescription(location); + bool fromCache = false; + qint64 newTimeStamp = 0; + if (d->ModuleCache) + { + newTimeStamp = backend->timeStamp(location); + if (d->ModuleCache->timeStamp(location) < newTimeStamp) + { + // newly fetch the XML description + try + { + xml = backend->rawXmlDescription(location); + } + catch (...) + { + // cache the failed attempt + d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray()); + throw; + } + } + else + { + // use the cached XML description + xml = d->ModuleCache->rawXmlDescription(location); + fromCache = true; + } + } + else + { + xml = backend->rawXmlDescription(location); + } + if (xml.isEmpty()) { + if (!fromCache && d->ModuleCache) + { + d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray()); + } throw ctkInvalidArgumentException(QString("No XML output available from ") + location.toString()); } @@ -131,6 +188,12 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) ctkCmdLineModuleXmlValidator validator(&input); if (!validator.validateInput()) { + if (d->ModuleCache) + { + // validation failed, cache an empty description + d->ModuleCache->cacheXmlDescription(location, newTimeStamp, QByteArray()); + } + if (d->ValidationMode == STRICT_VALIDATION) { throw ctkInvalidArgumentException(QString("Validating module at %1 failed: %2") @@ -141,6 +204,22 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) ref.d->XmlValidationErrorString = validator.errorString(); } } + else + { + if (d->ModuleCache && newTimeStamp > 0) + { + // successfully validated the xml, cache it + d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml); + } + } + } + else + { + if (!fromCache && d->ModuleCache) + { + // cache it + d->ModuleCache->cacheXmlDescription(location, newTimeStamp, xml); + } } { @@ -167,6 +246,10 @@ void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& return; } d->LocationToRef.remove(ref.location()); + if (d->ModuleCache) + { + d->ModuleCache->removeCacheEntry(ref.location()); + } } emit moduleUnregistered(ref); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h index 3b7b3b00ce..9e34237444 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h @@ -56,7 +56,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject WEAK_VALIDATION }; - ctkCmdLineModuleManager(ValidationMode = STRICT_VALIDATION); + ctkCmdLineModuleManager(ValidationMode = STRICT_VALIDATION, const QString& cacheDir = QString()); ~ctkCmdLineModuleManager(); From efe1e7e358ef903505a1a4dc8aed11fe0c759fe3 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Mon, 20 Aug 2012 23:55:33 +0200 Subject: [PATCH 122/247] Fixed formatting of what() exception message. --- Libs/Core/ctkException.cpp | 14 ++++++++------ Libs/Core/ctkException.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Libs/Core/ctkException.cpp b/Libs/Core/ctkException.cpp index 30dfb91ea7..4b4a12749e 100644 --- a/Libs/Core/ctkException.cpp +++ b/Libs/Core/ctkException.cpp @@ -105,14 +105,16 @@ const char* ctkException::className() const throw() // -------------------------------------------------------------------------- const char* ctkException::what() const throw() { - static std::string txt; - txt = std::string(name()); - if (!Msg.isEmpty()) + if (WhatMsg.empty()) { - txt += ": "; - txt += Msg.toStdString(); + WhatMsg = std::string(name()); + if (!Msg.isEmpty()) + { + WhatMsg += ": "; + WhatMsg += Msg.toStdString(); + } } - return txt.c_str(); + return WhatMsg.c_str(); } // -------------------------------------------------------------------------- diff --git a/Libs/Core/ctkException.h b/Libs/Core/ctkException.h index 0838bf9b01..8eb49a60fd 100644 --- a/Libs/Core/ctkException.h +++ b/Libs/Core/ctkException.h @@ -163,6 +163,7 @@ class CTK_CORE_EXPORT ctkException : public std::exception, public ctkBackTrace private: QString Msg; + mutable std::string WhatMsg; ctkException* NestedException; void printEnclosedStackTrace(QDebug dbg, const QList& enclosingTrace, From 6def9e93c277f1ef1e29e12b69cc7df2fcb4e7a7 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 00:47:52 +0200 Subject: [PATCH 123/247] Improved code style for consistency. --- ...dLineModuleBackendFPDescriptionPrivate.cpp | 1 + .../ctkCmdLineModuleBackendFPUtil.cpp | 7 ++++- ...ctkCmdLineModuleBackendFunctionPointer.cpp | 27 +++++++++++++++++++ .../ctkCmdLineModuleFunctionPointerTask.cpp | 3 +++ .../ctkCmdLineModuleBackendLocalProcess.cpp | 9 +++++++ .../ctkCmdLineModuleProcessTask.cpp | 13 +++++++++ .../Core/ctkCmdLineModuleBackend.cpp | 1 + .../ctkCmdLineModuleDefaultPathBuilder.cpp | 1 + .../Core/ctkCmdLineModuleFrontend.cpp | 11 ++++++++ .../Core/ctkCmdLineModuleFrontendFactory.cpp | 1 + .../Core/ctkCmdLineModuleManager.cpp | 9 +++++++ .../Core/ctkCmdLineModulePathBuilder.cpp | 1 + .../Core/ctkCmdLineModuleReference.cpp | 12 +++++++++ .../Core/ctkCmdLineModuleRunException.cpp | 12 +++++++++ .../Core/ctkCmdLineModuleXmlMsgHandler.cpp | 4 +++ .../ctkCmdLineModuleXmlProgressWatcher.cpp | 4 +++ .../Core/ctkCmdLineModuleXmlValidator.cpp | 10 +++++++ .../Core/ctkCmdLineModuleXslTransform.cpp | 17 ++++++++++++ .../ctkCmdLineModuleFrontendFactoryQtGui.cpp | 4 ++- .../ctkCmdLineModuleObjectTreeWalker.cpp | 24 +++++++++++++++++ ...tkCmdLineModuleFrontendFactoryQtWebKit.cpp | 4 ++- .../ctkCmdLineModuleFrontendQtWebKit.cpp | 4 +++ 22 files changed, 176 insertions(+), 3 deletions(-) diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp index 9a0f59669e..6050e7b4cc 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPDescriptionPrivate.cpp @@ -21,6 +21,7 @@ #include "ctkCmdLineModuleBackendFPDescriptionPrivate.h" +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate::xmlDescription() const { QString xml; diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp index 9941465175..204e5b0f4d 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil.cpp @@ -25,25 +25,29 @@ namespace ctk { namespace CmdLineModuleBackendFunctionPointer { +//---------------------------------------------------------------------------- FunctionPointerHolderBase::~FunctionPointerHolderBase() { } - +//---------------------------------------------------------------------------- FunctionPointerProxy::FunctionPointerProxy() : FpHolder(NULL) {} +//---------------------------------------------------------------------------- FunctionPointerProxy::~FunctionPointerProxy() { delete FpHolder; } +//---------------------------------------------------------------------------- FunctionPointerProxy::FunctionPointerProxy(const FunctionPointerProxy& other) : FpHolder(other.FpHolder->clone()) { } +//---------------------------------------------------------------------------- FunctionPointerProxy& FunctionPointerProxy::operator=(const FunctionPointerProxy& other) { delete this->FpHolder; @@ -51,6 +55,7 @@ FunctionPointerProxy& FunctionPointerProxy::operator=(const FunctionPointerProxy return *this; } +//---------------------------------------------------------------------------- void FunctionPointerProxy::call(const QList &args) { FpHolder->call(args); diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp index 3c53d969c0..eae779baeb 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp @@ -37,12 +37,14 @@ namespace ctk { namespace CmdLineModuleBackendFunctionPointer { +//---------------------------------------------------------------------------- template<> CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName() { return "integer"; } +//---------------------------------------------------------------------------- template<> CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName >() { @@ -52,6 +54,7 @@ CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName >() } } +//---------------------------------------------------------------------------- void CalculateFibonacciNumbers(int level) //, QList* result) { qDebug() << "Number: 0"; @@ -74,70 +77,84 @@ void CalculateFibonacciNumbers(int level) //, QList* result) } } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendFunctionPointer::Description::Description() : d(new ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendFunctionPointer::Description::~Description() { } +//---------------------------------------------------------------------------- QUrl ctkCmdLineModuleBackendFunctionPointer::Description::moduleLocation() const { return d->ModuleLocation; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleCategory() const { return d->ModuleCategory; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleCategory(const QString& category) { d->ModuleCategory = category; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleTitle() const { return d->ModuleTitle; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleTitle(const QString &title) { d->ModuleTitle = title; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleDescription() const { return d->ModuleDescription; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleDescription(const QString &description) { d->ModuleDescription = description; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleVersion() const { return d->ModuleVersion; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleVersion(const QString &version) { d->ModuleVersion = version; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::Description::moduleContributor() const { return d->ModuleContributor; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleBackendFunctionPointer::Description::setModuleContributor(const QString &contributor) { d->ModuleContributor = contributor; } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendFunctionPointer::Description::Description(const QUrl &location, const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy &fpProxy) : d(new ctkCmdLineModuleBackendFunctionPointer::DescriptionPrivate) @@ -146,45 +163,53 @@ ctkCmdLineModuleBackendFunctionPointer::Description::Description(const QUrl &loc d->FpProxy = fpProxy; } +//---------------------------------------------------------------------------- struct ctkCmdLineModuleBackendFunctionPointerPrivate { QHash UrlToFpDescription; }; +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendFunctionPointer::ctkCmdLineModuleBackendFunctionPointer() : d(new ctkCmdLineModuleBackendFunctionPointerPrivate) { this->registerFunctionPointer("Fibonacci Number", CalculateFibonacciNumbers, "Count"); } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::name() const { return "Function Pointer (experimental)"; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::description() const { return "Calls a previously registered function pointer."; } +//---------------------------------------------------------------------------- QList ctkCmdLineModuleBackendFunctionPointer::schemes() const { static QList supportedSchemes = QList() << "fp"; return supportedSchemes; } +//---------------------------------------------------------------------------- qint64 ctkCmdLineModuleBackendFunctionPointer::timeStamp(const QUrl &location) const { Q_UNUSED(location) return 0; } +//---------------------------------------------------------------------------- QByteArray ctkCmdLineModuleBackendFunctionPointer::rawXmlDescription(const QUrl& location) { if (!d->UrlToFpDescription.contains(location)) return QByteArray(); return QByteArray(qPrintable(d->UrlToFpDescription[location].d->xmlDescription())); } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleBackendFunctionPointer::run(ctkCmdLineModuleFrontend *frontend) { QUrl url = frontend->location(); @@ -198,11 +223,13 @@ ctkCmdLineModuleFuture ctkCmdLineModuleBackendFunctionPointer::run(ctkCmdLineMod return fpTask->start(); } +//---------------------------------------------------------------------------- QList ctkCmdLineModuleBackendFunctionPointer::registeredFunctionPointers() const { return d->UrlToFpDescription.keys(); } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendFunctionPointer::Description* ctkCmdLineModuleBackendFunctionPointer::registerFunctionPointerProxy(const QString& title, const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy& proxy, diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp index 6af0352cc0..ffbe5dc9d3 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask.cpp @@ -26,12 +26,14 @@ #include "ctkCmdLineModuleFuture.h" #include "ctkCmdLineModuleRunException.h" +//---------------------------------------------------------------------------- ctkCmdLineModuleFunctionPointerTask::ctkCmdLineModuleFunctionPointerTask(const ctkCmdLineModuleBackendFunctionPointer::Description &fpDescr, const QList ¶mValues) : FpDescription(fpDescr) , ParamValues(paramValues) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleFunctionPointerTask::start() { this->setRunnable(this); @@ -42,6 +44,7 @@ ctkCmdLineModuleFuture ctkCmdLineModuleFunctionPointerTask::start() return future; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleFunctionPointerTask::run() { if (this->isCanceled()) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp index 16355bb369..d8147bd15d 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.cpp @@ -35,6 +35,7 @@ #include #include +//---------------------------------------------------------------------------- struct ctkCmdLineModuleBackendLocalProcessPrivate { @@ -119,30 +120,36 @@ struct ctkCmdLineModuleBackendLocalProcessPrivate } }; +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendLocalProcess::ctkCmdLineModuleBackendLocalProcess() : d(new ctkCmdLineModuleBackendLocalProcessPrivate){ } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackendLocalProcess::~ctkCmdLineModuleBackendLocalProcess() { } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendLocalProcess::name() const { return "Local Process"; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendLocalProcess::description() const { return "Runs an executable command line module using a local process."; } +//---------------------------------------------------------------------------- QList ctkCmdLineModuleBackendLocalProcess::schemes() const { static QList supportedSchemes = QList() << "file"; return supportedSchemes; } +//---------------------------------------------------------------------------- qint64 ctkCmdLineModuleBackendLocalProcess::timeStamp(const QUrl &location) const { QFileInfo fileInfo(location.toLocalFile()); @@ -154,6 +161,7 @@ qint64 ctkCmdLineModuleBackendLocalProcess::timeStamp(const QUrl &location) cons return 0; } +//---------------------------------------------------------------------------- QByteArray ctkCmdLineModuleBackendLocalProcess::rawXmlDescription(const QUrl &location) { QProcess process; @@ -170,6 +178,7 @@ QByteArray ctkCmdLineModuleBackendLocalProcess::rawXmlDescription(const QUrl &lo return process.readAllStandardOutput(); } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleBackendLocalProcess::run(ctkCmdLineModuleFrontend* frontend) { QStringList args = d->commandLineArguments(frontend->values(), frontend->moduleReference().description()); diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp index 9bc2e03c58..b6a0065166 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp @@ -33,6 +33,7 @@ #include #endif +//---------------------------------------------------------------------------- ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location, ctkCmdLineModuleFutureInterface &futureInterface) : process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process), @@ -58,27 +59,32 @@ ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process futureWatcher.setFuture(futureInterface.future()); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::filterStarted(const QString& name, const QString& comment) { Q_UNUSED(comment) futureInterface.setProgressValueAndText(incrementProgress(), name); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::filterProgress(float progress) { futureInterface.setProgressValue(updateProgress(progress)); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::filterFinished(const QString& name) { futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::filterXmlError(const QString &error) { qDebug().nospace() << "[Module " << location << "]: " << error; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::pauseProcess() { if (processPaused || !futureInterface.isPaused()) return; @@ -96,6 +102,7 @@ void ctkCmdLineModuleProcessWatcher::pauseProcess() #endif } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::resumeProcess() { if (!processPaused) return; @@ -113,6 +120,7 @@ void ctkCmdLineModuleProcessWatcher::resumeProcess() #endif } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::cancelProcess() { process.terminate(); @@ -129,12 +137,14 @@ int ctkCmdLineModuleProcessWatcher::updateProgress(float progress) return progressValue; } +//---------------------------------------------------------------------------- int ctkCmdLineModuleProcessWatcher::incrementProgress() { if (++progressValue > 999) progressValue = 999; return progressValue; } +//---------------------------------------------------------------------------- ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args) : location(location), args(args) { @@ -144,10 +154,12 @@ ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location #endif } +//---------------------------------------------------------------------------- ctkCmdLineModuleProcessTask::~ctkCmdLineModuleProcessTask() { } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleProcessTask::start() { this->setRunnable(this); @@ -157,6 +169,7 @@ ctkCmdLineModuleFuture ctkCmdLineModuleProcessTask::start() return future; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleProcessTask::run() { if (this->isCanceled()) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp index 3af25f827f..56219ef4ef 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.cpp @@ -21,6 +21,7 @@ #include "ctkCmdLineModuleBackend.h" +//---------------------------------------------------------------------------- ctkCmdLineModuleBackend::~ctkCmdLineModuleBackend() { } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp index f9ec4ee77e..0c539aa217 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp @@ -25,6 +25,7 @@ #include #include +//---------------------------------------------------------------------------- struct ctkCmdLineModuleDefaultPathBuilderPrivate { public: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp index 700f7f717c..68d882335a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp @@ -29,6 +29,7 @@ #include +//---------------------------------------------------------------------------- struct ctkCmdLineModuleFrontendPrivate { ctkCmdLineModuleFrontendPrivate(const ctkCmdLineModuleReference& moduleRef) @@ -44,16 +45,19 @@ struct ctkCmdLineModuleFrontendPrivate }; +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontend::ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef) : d(new ctkCmdLineModuleFrontendPrivate(moduleRef)) { } +//---------------------------------------------------------------------------- void ctkCmdLineModuleFrontend::setFuture(const ctkCmdLineModuleFuture &future) { d->Future = future; } +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontend::~ctkCmdLineModuleFrontend() { } @@ -73,31 +77,37 @@ QList ctkCmdLineModuleFrontend::parameterNames() const return d->ParameterNames; } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference ctkCmdLineModuleFrontend::moduleReference() const { return d->ModuleReference; } +//---------------------------------------------------------------------------- QUrl ctkCmdLineModuleFrontend::location() const { return d->ModuleReference.location(); } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleFrontend::future() const { return d->Future; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleFrontend::isRunning() const { return d->Future.isRunning(); } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleFrontend::isPaused() const { return d->Future.isPaused(); } +//---------------------------------------------------------------------------- QHash ctkCmdLineModuleFrontend::values() const { QHash result; @@ -108,6 +118,7 @@ QHash ctkCmdLineModuleFrontend::values() const return result; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleFrontend::setValues(const QHash &values) { QHashIterator iter(values); diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp index 502a2c5c4f..e96b51071f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.cpp @@ -22,6 +22,7 @@ #include "ctkCmdLineModuleFrontendFactory.h" +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontendFactory::~ctkCmdLineModuleFrontendFactory() { } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 2cb84f85c6..39a76daabc 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -42,6 +42,7 @@ #include +//---------------------------------------------------------------------------- struct ctkCmdLineModuleManagerPrivate { ctkCmdLineModuleManagerPrivate(ctkCmdLineModuleManager::ValidationMode mode, const QString& cacheDir) @@ -83,15 +84,18 @@ struct ctkCmdLineModuleManagerPrivate const ctkCmdLineModuleManager::ValidationMode ValidationMode; }; +//---------------------------------------------------------------------------- ctkCmdLineModuleManager::ctkCmdLineModuleManager(ValidationMode validationMode, const QString& cacheDir) : d(new ctkCmdLineModuleManagerPrivate(validationMode, cacheDir)) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleManager::~ctkCmdLineModuleManager() { } +//---------------------------------------------------------------------------- void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend) { QMutexLocker lock(&d->Mutex); @@ -115,6 +119,7 @@ void ctkCmdLineModuleManager::registerBackend(ctkCmdLineModuleBackend *backend) } } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference ctkCmdLineModuleManager::registerModule(const QUrl &location) { @@ -237,6 +242,7 @@ ctkCmdLineModuleManager::registerModule(const QUrl &location) return ref; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& ref) { { @@ -254,18 +260,21 @@ void ctkCmdLineModuleManager::unregisterModule(const ctkCmdLineModuleReference& emit moduleUnregistered(ref); } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference ctkCmdLineModuleManager::moduleReference(const QUrl &location) const { QMutexLocker lock(&d->Mutex); return d->LocationToRef[location]; } +//---------------------------------------------------------------------------- QList ctkCmdLineModuleManager::moduleReferences() const { QMutexLocker lock(&d->Mutex); return d->LocationToRef.values(); } +//---------------------------------------------------------------------------- ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *frontend) { QMutexLocker lock(&d->Mutex); diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp index 4b3374862e..6af74eaea6 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.cpp @@ -21,6 +21,7 @@ #include "ctkCmdLineModulePathBuilder.h" +//---------------------------------------------------------------------------- ctkCmdLineModulePathBuilder::~ctkCmdLineModulePathBuilder() { } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp index ce38e60374..00bce92b8e 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp @@ -26,11 +26,13 @@ #include +//---------------------------------------------------------------------------- ctkCmdLineModuleReferencePrivate::ctkCmdLineModuleReferencePrivate() : Backend(NULL) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleDescription ctkCmdLineModuleReferencePrivate::description() const { // Lazy creation. The title is a required XML element. @@ -44,50 +46,60 @@ ctkCmdLineModuleDescription ctkCmdLineModuleReferencePrivate::description() cons return Description; } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference::ctkCmdLineModuleReference() : d(new ctkCmdLineModuleReferencePrivate()) {} +//---------------------------------------------------------------------------- ctkCmdLineModuleReference::~ctkCmdLineModuleReference() { } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference::ctkCmdLineModuleReference(const ctkCmdLineModuleReference &ref) : d(ref.d) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference &ctkCmdLineModuleReference::operator =(const ctkCmdLineModuleReference &ref) { d = ref.d; return *this; } +//---------------------------------------------------------------------------- ctkCmdLineModuleReference::operator bool() { return !d->RawXmlDescription.isEmpty(); } +//---------------------------------------------------------------------------- ctkCmdLineModuleDescription ctkCmdLineModuleReference::description() const { return d->description(); } +//---------------------------------------------------------------------------- QByteArray ctkCmdLineModuleReference::rawXmlDescription() const { return d->RawXmlDescription; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleReference::xmlValidationErrorString() const { return d->XmlValidationErrorString; } +//---------------------------------------------------------------------------- QUrl ctkCmdLineModuleReference::location() const { return d->Location; } +//---------------------------------------------------------------------------- ctkCmdLineModuleBackend *ctkCmdLineModuleReference::backend() const { return d->Backend; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp index f9329aecf7..7b993fa99c 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.cpp @@ -23,6 +23,7 @@ #include +//---------------------------------------------------------------------------- ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, int errorCode, const QString &errorString) : QtConcurrent::Exception(), ctkException(QString("Running module \"%1\" failed with code %2: %3").arg(location.toString()).arg(errorCode).arg(errorString)), @@ -30,6 +31,7 @@ ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, { } +//---------------------------------------------------------------------------- ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, int errorCode, const QString &errorString, const ctkCmdLineModuleRunException& cause) : QtConcurrent::Exception(), ctkException(location.toString(), cause), @@ -37,51 +39,61 @@ ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const QUrl &location, { } +//---------------------------------------------------------------------------- ctkCmdLineModuleRunException::ctkCmdLineModuleRunException(const ctkCmdLineModuleRunException& o) : QtConcurrent::Exception(o), ctkException(o), Location(o.Location), ErrorCode(o.ErrorCode), ErrorString(o.ErrorString) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleRunException::~ctkCmdLineModuleRunException() throw() { } +//---------------------------------------------------------------------------- QUrl ctkCmdLineModuleRunException::location() const throw() { return Location; } +//---------------------------------------------------------------------------- int ctkCmdLineModuleRunException::errorCode() const throw() { return ErrorCode; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleRunException::errorString() const throw() { return ErrorString; } +//---------------------------------------------------------------------------- const char* ctkCmdLineModuleRunException::name() const throw() { return "CTK CommandLineModule Run Exception"; } +//---------------------------------------------------------------------------- const char* ctkCmdLineModuleRunException::className() const throw() { return "ctkCmdLineModuleRunException"; } +//---------------------------------------------------------------------------- ctkCmdLineModuleRunException* ctkCmdLineModuleRunException::clone() const { return new ctkCmdLineModuleRunException(*this); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleRunException::rethrow() const { throw *this; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleRunException::raise() const { throw *this; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler.cpp index 797fdae131..01537dbf12 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler.cpp @@ -23,21 +23,25 @@ #include +//---------------------------------------------------------------------------- QString ctkCmdLineModuleXmlMsgHandler::statusMessage() const { return Description; } +//---------------------------------------------------------------------------- int ctkCmdLineModuleXmlMsgHandler::line() const { return SourceLocation.line(); } +//---------------------------------------------------------------------------- int ctkCmdLineModuleXmlMsgHandler::column() const { return SourceLocation.column(); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXmlMsgHandler::handleMessage(QtMsgType type, const QString& description, const QUrl& identifier, const QSourceLocation& sourceLocation) { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index 0659cf0942..0be65d2d09 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -36,6 +36,7 @@ static QString FILTER_END = "filter-end"; } +//---------------------------------------------------------------------------- class ctkCmdLineModuleXmlProgressWatcherPrivate { public: @@ -182,6 +183,8 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate float currentProgress; }; + +//---------------------------------------------------------------------------- ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice* input) : d(new ctkCmdLineModuleXmlProgressWatcherPrivate(input, this)) { @@ -194,6 +197,7 @@ ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice connect(d->input, SIGNAL(readyRead()), SLOT(_q_readyRead())); } +//---------------------------------------------------------------------------- ctkCmdLineModuleXmlProgressWatcher::~ctkCmdLineModuleXmlProgressWatcher() { } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp index 9f2f9103dc..86f3106d10 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.cpp @@ -30,6 +30,7 @@ #include +//---------------------------------------------------------------------------- class ctkCmdLineModuleXmlValidatorPrivate { public: @@ -44,31 +45,38 @@ class ctkCmdLineModuleXmlValidatorPrivate QString ErrorStr; }; + +//---------------------------------------------------------------------------- ctkCmdLineModuleXmlValidator::ctkCmdLineModuleXmlValidator(QIODevice *input) : d(new ctkCmdLineModuleXmlValidatorPrivate) { d->Input = input; } +//---------------------------------------------------------------------------- ctkCmdLineModuleXmlValidator::~ctkCmdLineModuleXmlValidator() { } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXmlValidator::setInput(QIODevice *input) { d->Input = input; } +//---------------------------------------------------------------------------- QIODevice* ctkCmdLineModuleXmlValidator::input() const { return d->Input; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXmlValidator::setInputSchema(QIODevice *input) { d->InputSchema = input; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXmlValidator::validateInput() { d->ErrorStr.clear(); @@ -112,11 +120,13 @@ bool ctkCmdLineModuleXmlValidator::validateInput() return true; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXmlValidator::error() const { return !d->ErrorStr.isEmpty(); } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleXmlValidator::errorString() const { return d->ErrorStr; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp index 3dedc97acc..0fc37b503a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp @@ -32,6 +32,7 @@ #include "ctkCmdLineModuleXslTransform.h" #include "ctkCmdLineModuleXmlMsgHandler_p.h" +//---------------------------------------------------------------------------- class ctkCmdLineModuleXslTransformPrivate { public: @@ -63,6 +64,7 @@ class ctkCmdLineModuleXslTransformPrivate QString ErrorStr; }; +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXslTransformPrivate::validateOutput() { this->ErrorStr.clear(); @@ -108,6 +110,7 @@ bool ctkCmdLineModuleXslTransformPrivate::validateOutput() return true; } +//---------------------------------------------------------------------------- ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIODevice *output) : ctkCmdLineModuleXmlValidator(input) , d(new ctkCmdLineModuleXslTransformPrivate(output)) @@ -128,35 +131,42 @@ ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIO this->bindVariable("unsupportedWidget", QVariant(QString("QLabel"))); } +//---------------------------------------------------------------------------- ctkCmdLineModuleXslTransform::~ctkCmdLineModuleXslTransform() { } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setOutput(QIODevice* output) { d->Output = output; } +//---------------------------------------------------------------------------- QIODevice* ctkCmdLineModuleXslTransform::output() const { return d->Output; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setOutputSchema(QIODevice *output) { d->OutputSchema = output; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXslTransform::formatXmlOutput() const { return d->Format; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setFormatXmlOutput(bool format) { d->Format = format; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXslTransform::transform() { d->ErrorStr.clear(); @@ -251,16 +261,19 @@ bool ctkCmdLineModuleXslTransform::transform() return true; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setXslTransformation(QIODevice *transformation) { d->Transformation = transformation; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::bindVariable(const QString& name, const QVariant& value) { d->XslTransform.bindVariable(name, value); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transformation) { QList transformations; @@ -268,21 +281,25 @@ void ctkCmdLineModuleXslTransform::setXslExtraTransformation(QIODevice* transfor this->setXslExtraTransformations(transformations); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setXslExtraTransformations(const QList& transformations) { d->ExtraTransformations = transformations; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleXslTransform::setValidateOutput(bool validate) { d->Validate = validate; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleXslTransform::error() const { return ctkCmdLineModuleXmlValidator::error() || !d->ErrorStr.isEmpty(); } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleXslTransform::errorString() const { QString errStr = this->ctkCmdLineModuleXmlValidator::errorString(); diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp index ff565e4485..f5e9a487e7 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.cpp @@ -23,17 +23,19 @@ #include "ctkCmdLineModuleFrontendQtGui.h" +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontendQtGui *ctkCmdLineModuleFrontendFactoryQtGui::create(const ctkCmdLineModuleReference &moduleRef) { return new ctkCmdLineModuleFrontendQtGui(moduleRef); } - +//---------------------------------------------------------------------------- QString ctkCmdLineModuleFrontendFactoryQtGui::name() const { return "Qt Gui"; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleFrontendFactoryQtGui::description() const { return "A frontend using the QtGui library."; diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp index f79105bdf9..25e0117784 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp @@ -33,22 +33,26 @@ static QString PREFIX_PARAMETER = "parameter:"; } +//---------------------------------------------------------------------------- ctkCmdLineModuleObjectTreeWalker::ctkCmdLineModuleObjectTreeWalker(QObject *root) : RootObject(root), CurrentObject(0), CurrentToken(NoToken), AtEnd(false) { } +//---------------------------------------------------------------------------- ctkCmdLineModuleObjectTreeWalker::~ctkCmdLineModuleObjectTreeWalker() { } +//---------------------------------------------------------------------------- void ctkCmdLineModuleObjectTreeWalker::setRootObject(QObject* root) { RootObject = root; clear(); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleObjectTreeWalker::clear() { CurrentToken = NoToken; @@ -56,21 +60,25 @@ void ctkCmdLineModuleObjectTreeWalker::clear() ObjectStack.clear(); } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::atEnd() const { return AtEnd || RootObject == 0; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::isParameterGroup() const { return CurrentToken == ParameterGroup; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::isParameter() const { return CurrentToken == Parameter; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleObjectTreeWalker::name() const { if (CurrentObject == 0) return QString(); @@ -83,6 +91,7 @@ QString ctkCmdLineModuleObjectTreeWalker::name() const } } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleObjectTreeWalker::label() const { if (CurrentObject == 0) return QString(); @@ -95,12 +104,14 @@ QString ctkCmdLineModuleObjectTreeWalker::label() const } } +//---------------------------------------------------------------------------- QVariant ctkCmdLineModuleObjectTreeWalker::value() const { QString valProp = property("valueProperty").toString(); return property(valProp); } +//---------------------------------------------------------------------------- void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value) { QVariant valProp = property("valueProperty"); @@ -110,30 +121,35 @@ void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value) } } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleObjectTreeWalker::flag() const { QVariant v = property("flag"); return v.isValid() ? v.toString() : QString(); } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleObjectTreeWalker::longFlag() const { QVariant v = property("longflag"); return v.isValid() ? v.toString() : QString(); } +//---------------------------------------------------------------------------- int ctkCmdLineModuleObjectTreeWalker::index() const { QVariant v = property("index"); return v.isValid() ? v.toInt() : -1; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::isMultiple() const { QVariant v = property("multiple"); return v.isValid() ? v.toBool() : false; } +//---------------------------------------------------------------------------- QVariant ctkCmdLineModuleObjectTreeWalker::property(const QString &propName) const { if (CurrentObject == 0) return QVariant(); @@ -145,6 +161,7 @@ QVariant ctkCmdLineModuleObjectTreeWalker::property(const QString &propName) con return res; } +//---------------------------------------------------------------------------- ctkCmdLineModuleObjectTreeWalker::TokenType ctkCmdLineModuleObjectTreeWalker::readNext() { if (AtEnd) return NoToken; @@ -195,29 +212,34 @@ ctkCmdLineModuleObjectTreeWalker::TokenType ctkCmdLineModuleObjectTreeWalker::re return NoToken; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::readNextExecutable() { while (!(readNext() == Executable || AtEnd)); return !AtEnd; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::readNextParameterGroup() { while (!(readNext() == ParameterGroup || AtEnd)); return !AtEnd; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::readNextParameter() { while (!(readNext() == Parameter || AtEnd)); return !AtEnd; } +//---------------------------------------------------------------------------- ctkCmdLineModuleObjectTreeWalker::TokenType ctkCmdLineModuleObjectTreeWalker::tokenType() const { return CurrentToken; } +//---------------------------------------------------------------------------- QVariant ctkCmdLineModuleObjectTreeWalker::prefixedProperty(const QString& propName) const { if (CurrentObject == 0) return QString(); @@ -234,6 +256,7 @@ QVariant ctkCmdLineModuleObjectTreeWalker::prefixedProperty(const QString& propN return CurrentObject->property(qPrintable(prefixedName)); } +//---------------------------------------------------------------------------- ctkCmdLineModuleObjectTreeWalker::TokenType ctkCmdLineModuleObjectTreeWalker::token(QObject* obj) { @@ -245,6 +268,7 @@ ctkCmdLineModuleObjectTreeWalker::token(QObject* obj) return ctkCmdLineModuleObjectTreeWalker::NoToken; } +//---------------------------------------------------------------------------- bool ctkCmdLineModuleObjectTreeWalker::setCurrent(QObject* obj) { ctkCmdLineModuleObjectTreeWalker::TokenType t = token(obj); diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp index eb47772507..0bee4372fd 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp @@ -22,17 +22,19 @@ #include "ctkCmdLineModuleFrontendFactoryQtWebKit.h" +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontendQtWebKit *ctkCmdLineModuleFrontendFactoryQtWebKit::create(const ctkCmdLineModuleReference &moduleRef) { return new ctkCmdLineModuleFrontendQtWebKit(moduleRef); } - +//---------------------------------------------------------------------------- QString ctkCmdLineModuleFrontendFactoryQtWebKit::name() const { return "Qt WebKit (experimental)"; } +//---------------------------------------------------------------------------- QString ctkCmdLineModuleFrontendFactoryQtWebKit::description() const { return "An experimental frontend using the QtWebKit library."; diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp index e7a0cdf52a..2cbc28bb8a 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp @@ -32,6 +32,7 @@ #include +//---------------------------------------------------------------------------- ctkCmdLineModuleFrontendQtWebKit::ctkCmdLineModuleFrontendQtWebKit(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleFrontend(moduleRef) , WebView(NULL) @@ -39,6 +40,7 @@ ctkCmdLineModuleFrontendQtWebKit::ctkCmdLineModuleFrontendQtWebKit(const ctkCmdL } +//---------------------------------------------------------------------------- QObject* ctkCmdLineModuleFrontendQtWebKit::guiHandle() const { if (WebView) return WebView; @@ -65,6 +67,7 @@ QObject* ctkCmdLineModuleFrontendQtWebKit::guiHandle() const return this->WebView; } +//---------------------------------------------------------------------------- QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter) const { QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]"); @@ -75,6 +78,7 @@ QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter) const return value; } +//---------------------------------------------------------------------------- void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString ¶meter, const QVariant &value) { if (!this->WebView) return; From a03a6136acd9115adb14a2d2b610f541d43fd38c Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 01:11:38 +0200 Subject: [PATCH 124/247] Cleaned up APIs for existing frontends and backends. --- .../Backend/LocalProcess/CMakeLists.txt | 3 + .../ctkCmdLineModuleProcessTask.cpp | 130 ++-------------- .../ctkCmdLineModuleProcessTask.h | 45 +----- .../ctkCmdLineModuleProcessWatcher.cpp | 141 ++++++++++++++++++ .../ctkCmdLineModuleProcessWatcher_p.h | 72 +++++++++ .../QtGui/ctkCmdLineModuleFrontendQtGui.cpp | 65 +++++--- .../QtGui/ctkCmdLineModuleFrontendQtGui.h | 14 +- .../Frontend/QtWebKit/CMakeLists.txt | 1 + ...tkCmdLineModuleFrontendFactoryQtWebKit.cpp | 3 +- .../ctkCmdLineModuleFrontendFactoryQtWebKit.h | 3 +- .../ctkCmdLineModuleFrontendQtWebKit.cpp | 2 +- ...h => ctkCmdLineModuleFrontendQtWebKit_p.h} | 0 12 files changed, 291 insertions(+), 188 deletions(-) create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h rename Libs/CommandLineModules/Frontend/QtWebKit/{ctkCmdLineModuleFrontendQtWebKit.h => ctkCmdLineModuleFrontendQtWebKit_p.h} (100%) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt index 96dafd8961..186c6faeba 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt +++ b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt @@ -16,11 +16,14 @@ set(KIT_export_directive "CTK_CMDLINEMODULEBACKENDLP_EXPORT") set(KIT_SRCS ctkCmdLineModuleBackendLocalProcess.cpp ctkCmdLineModuleProcessTask.cpp + ctkCmdLineModuleProcessWatcher.cpp + ctkCmdLineModuleProcessWatcher_p.h ) # Headers that should run through moc set(KIT_MOC_SRCS ctkCmdLineModuleProcessTask.h + ctkCmdLineModuleProcessWatcher_p.h ) # UI files diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp index b6a0065166..02498804c1 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp @@ -20,6 +20,7 @@ =============================================================================*/ #include "ctkCmdLineModuleProcessTask.h" +#include "ctkCmdLineModuleProcessWatcher_p.h" #include "ctkCmdLineModuleRunException.h" #include "ctkCmdLineModuleXmlProgressWatcher.h" #include "ctkCmdLineModuleFuture.h" @@ -29,124 +30,21 @@ #include #include -#ifdef Q_OS_UNIX -#include -#endif - -//---------------------------------------------------------------------------- -ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location, - ctkCmdLineModuleFutureInterface &futureInterface) - : process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process), - processPaused(false), progressValue(0) -{ - futureInterface.setProgressRange(0, 1000); - - connect(&processXmlWatcher, SIGNAL(filterStarted(QString,QString)), SLOT(filterStarted(QString,QString))); - connect(&processXmlWatcher, SIGNAL(filterProgress(float)), SLOT(filterProgress(float))); - connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString))); - connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString))); - - connect(&futureWatcher, SIGNAL(canceled()), SLOT(cancelProcess())); -#ifdef Q_OS_UNIX - connect(&futureWatcher, SIGNAL(resumed()), SLOT(resumeProcess())); - // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is - // not emitted directly when the QFuture is paused. Instead, it is emitted after - // resuming the future, after the "resume" signal has been emitted... - //connect(&futureWatcher, SIGNAL(paused()), SLOT(pauseProcess())); - connect(&pollPauseTimer, SIGNAL(timeout()), this, SLOT(pauseProcess())); - pollPauseTimer.start(500); -#endif - futureWatcher.setFuture(futureInterface.future()); -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::filterStarted(const QString& name, const QString& comment) -{ - Q_UNUSED(comment) - futureInterface.setProgressValueAndText(incrementProgress(), name); -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::filterProgress(float progress) -{ - futureInterface.setProgressValue(updateProgress(progress)); -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::filterFinished(const QString& name) -{ - futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name); -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::filterXmlError(const QString &error) -{ - qDebug().nospace() << "[Module " << location << "]: " << error; -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::pauseProcess() -{ - if (processPaused || !futureInterface.isPaused()) return; - -#ifdef Q_OS_UNIX - if (::kill(process.pid(), SIGSTOP)) - { - // error - futureInterface.setPaused(false); - } - else - { - processPaused = true; - } -#endif -} - -//---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::resumeProcess() -{ - if (!processPaused) return; - -#ifdef Q_OS_UNIX - if(::kill(process.pid(), SIGCONT)) - { - // error - futureInterface.setPaused(true); - } - else - { - processPaused = false; - } -#endif -} - //---------------------------------------------------------------------------- -void ctkCmdLineModuleProcessWatcher::cancelProcess() +struct ctkCmdLineModuleProcessTaskPrivate { - process.terminate(); -} - -int ctkCmdLineModuleProcessWatcher::updateProgress(float progress) -{ - progressValue = static_cast(progress * 1000.0f); - // normalize the value to lie between 0 and 1000. - // 0 is reported when the process starts and 1000 is reserved for - // reporting completion + standard output text - if (progressValue < 1) progressValue = 1; - if (progressValue > 999) progressValue = 999; - return progressValue; -} + ctkCmdLineModuleProcessTaskPrivate(const QString& location, const QStringList& args) + : Location(location) + , Args(args) + {} -//---------------------------------------------------------------------------- -int ctkCmdLineModuleProcessWatcher::incrementProgress() -{ - if (++progressValue > 999) progressValue = 999; - return progressValue; -} + const QString Location; + const QStringList Args; +}; //---------------------------------------------------------------------------- ctkCmdLineModuleProcessTask::ctkCmdLineModuleProcessTask(const QString& location, const QStringList& args) - : location(location), args(args) + : d(new ctkCmdLineModuleProcessTaskPrivate(location, args)) { this->setCanCancel(true); #ifdef Q_OS_UNIX @@ -185,20 +83,20 @@ void ctkCmdLineModuleProcessTask::run() QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit())); QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit())); - process.start(location, args); + process.start(d->Location, d->Args); - ctkCmdLineModuleProcessWatcher progressWatcher(process, location, *this); + ctkCmdLineModuleProcessWatcher progressWatcher(process, d->Location, *this); Q_UNUSED(progressWatcher) localLoop.exec(); if (process.error() != QProcess::UnknownError) { - this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.errorString())); + this->reportException(ctkCmdLineModuleRunException(d->Location, process.exitCode(), process.errorString())); } else if (process.exitCode() != 0) { - this->reportException(ctkCmdLineModuleRunException(location, process.exitCode(), process.readAllStandardError())); + this->reportException(ctkCmdLineModuleRunException(d->Location, process.exitCode(), process.readAllStandardError())); } this->setProgressValueAndText(1000, process.readAllStandardError()); diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h index 2d44a4303e..9d2dc48c2b 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h @@ -22,9 +22,10 @@ #ifndef CTKCMDLINEMODULEPROCESSTASK_H #define CTKCMDLINEMODULEPROCESSTASK_H -#include "ctkCmdLineModuleXmlProgressWatcher.h" #include "ctkCmdLineModuleFutureInterface.h" +#include "ctkCommandLineModulesBackendLocalProcessExport.h" + #include #include #include @@ -34,7 +35,10 @@ class QProcess; -class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable +struct ctkCmdLineModuleProcessTaskPrivate; + +class CTK_CMDLINEMODULEBACKENDLP_EXPORT ctkCmdLineModuleProcessTask + : public ctkCmdLineModuleFutureInterface, public QRunnable { public: @@ -48,45 +52,10 @@ class ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, publ private: - const QString location; - const QStringList args; + QScopedPointer d; }; -class ctkCmdLineModuleProcessWatcher : public QObject -{ - Q_OBJECT - -public: - - ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location, - ctkCmdLineModuleFutureInterface& futureInterface); - -protected Q_SLOTS: - void filterStarted(const QString& name, const QString& comment); - void filterProgress(float progress); - void filterFinished(const QString& name); - - void filterXmlError(const QString& error); - - void pauseProcess(); - void resumeProcess(); - void cancelProcess(); - -private: - - int updateProgress(float progress); - int incrementProgress(); - - QProcess& process; - QString location; - ctkCmdLineModuleFutureInterface& futureInterface; - ctkCmdLineModuleXmlProgressWatcher processXmlWatcher; - QFutureWatcher futureWatcher; - QTimer pollPauseTimer; - bool processPaused; - int progressValue; -}; #endif // CTKCMDLINEMODULEPROCESSTASK_H diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp new file mode 100644 index 0000000000..fa450b857a --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp @@ -0,0 +1,141 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleProcessWatcher_p.h" + +#include "ctkCmdLineModuleFuture.h" + +#include + +#ifdef Q_OS_UNIX +#include +#endif + +//---------------------------------------------------------------------------- +ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location, + ctkCmdLineModuleFutureInterface &futureInterface) + : process(process), location(location), futureInterface(futureInterface), processXmlWatcher(&process), + processPaused(false), progressValue(0) +{ + futureInterface.setProgressRange(0, 1000); + + connect(&processXmlWatcher, SIGNAL(filterStarted(QString,QString)), SLOT(filterStarted(QString,QString))); + connect(&processXmlWatcher, SIGNAL(filterProgress(float)), SLOT(filterProgress(float))); + connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString))); + connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString))); + + connect(&futureWatcher, SIGNAL(canceled()), SLOT(cancelProcess())); +#ifdef Q_OS_UNIX + connect(&futureWatcher, SIGNAL(resumed()), SLOT(resumeProcess())); + // Due to Qt bug 12152, we cannot listen to the "paused" signal because it is + // not emitted directly when the QFuture is paused. Instead, it is emitted after + // resuming the future, after the "resume" signal has been emitted... + //connect(&futureWatcher, SIGNAL(paused()), SLOT(pauseProcess())); + connect(&pollPauseTimer, SIGNAL(timeout()), this, SLOT(pauseProcess())); + pollPauseTimer.start(500); +#endif + futureWatcher.setFuture(futureInterface.future()); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::filterStarted(const QString& name, const QString& comment) +{ + Q_UNUSED(comment) + futureInterface.setProgressValueAndText(incrementProgress(), name); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::filterProgress(float progress) +{ + futureInterface.setProgressValue(updateProgress(progress)); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::filterFinished(const QString& name) +{ + futureInterface.setProgressValueAndText(incrementProgress(), "Finished: " + name); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::filterXmlError(const QString &error) +{ + qDebug().nospace() << "[Module " << location << "]: " << error; +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::pauseProcess() +{ + if (processPaused || !futureInterface.isPaused()) return; + +#ifdef Q_OS_UNIX + if (::kill(process.pid(), SIGSTOP)) + { + // error + futureInterface.setPaused(false); + } + else + { + processPaused = true; + } +#endif +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::resumeProcess() +{ + if (!processPaused) return; + +#ifdef Q_OS_UNIX + if(::kill(process.pid(), SIGCONT)) + { + // error + futureInterface.setPaused(true); + } + else + { + processPaused = false; + } +#endif +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::cancelProcess() +{ + process.terminate(); +} + +int ctkCmdLineModuleProcessWatcher::updateProgress(float progress) +{ + progressValue = static_cast(progress * 1000.0f); + // normalize the value to lie between 0 and 1000. + // 0 is reported when the process starts and 1000 is reserved for + // reporting completion + standard output text + if (progressValue < 1) progressValue = 1; + if (progressValue > 999) progressValue = 999; + return progressValue; +} + +//---------------------------------------------------------------------------- +int ctkCmdLineModuleProcessWatcher::incrementProgress() +{ + if (++progressValue > 999) progressValue = 999; + return progressValue; +} diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h new file mode 100644 index 0000000000..f607fe4a36 --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h @@ -0,0 +1,72 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEPROCESSWATCHER_P_H +#define CTKCMDLINEMODULEPROCESSWATCHER_P_H + +#include "ctkCmdLineModuleXmlProgressWatcher.h" +#include "ctkCmdLineModuleFutureInterface.h" + +#include +#include +#include + +class ctkCmdLineModuleResult; + +class QProcess; + +class ctkCmdLineModuleProcessWatcher : public QObject +{ + Q_OBJECT + +public: + + ctkCmdLineModuleProcessWatcher(QProcess& process, const QString& location, + ctkCmdLineModuleFutureInterface& futureInterface); + +protected Q_SLOTS: + + void filterStarted(const QString& name, const QString& comment); + void filterProgress(float progress); + void filterFinished(const QString& name); + + void filterXmlError(const QString& error); + + void pauseProcess(); + void resumeProcess(); + void cancelProcess(); + +private: + + int updateProgress(float progress); + int incrementProgress(); + + QProcess& process; + QString location; + ctkCmdLineModuleFutureInterface& futureInterface; + ctkCmdLineModuleXmlProgressWatcher processXmlWatcher; + QFutureWatcher futureWatcher; + QTimer pollPauseTimer; + bool processPaused; + int progressValue; +}; + +#endif // CTKCMDLINEMODULEPROCESSWATCHER_P_H diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index 39a9900d36..c4ad6a46ac 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -34,12 +34,33 @@ #include +//----------------------------------------------------------------------------- +struct ctkCmdLineModuleFrontendQtGuiPrivate +{ + ctkCmdLineModuleFrontendQtGuiPrivate() + : Loader(NULL) + , Transform(NULL) + , Widget(NULL) + {} + + ~ctkCmdLineModuleFrontendQtGuiPrivate() + { + delete Loader; + delete Transform; + } + + mutable QUiLoader* Loader; + mutable ctkCmdLineModuleXslTransform* Transform; + mutable QWidget* Widget; + + // Cache the list of parameter names + mutable QList ParameterNames; +}; + //----------------------------------------------------------------------------- ctkCmdLineModuleFrontendQtGui::ctkCmdLineModuleFrontendQtGui(const ctkCmdLineModuleReference& moduleRef) : ctkCmdLineModuleFrontend(moduleRef), - Loader(NULL), - Transform(NULL), - Widget(NULL) + d(new ctkCmdLineModuleFrontendQtGuiPrivate) { } @@ -47,37 +68,35 @@ ctkCmdLineModuleFrontendQtGui::ctkCmdLineModuleFrontendQtGui(const ctkCmdLineMod //----------------------------------------------------------------------------- ctkCmdLineModuleFrontendQtGui::~ctkCmdLineModuleFrontendQtGui() { - delete this->Loader; - delete this->Transform; } //----------------------------------------------------------------------------- QUiLoader* ctkCmdLineModuleFrontendQtGui::uiLoader() const { - if (this->Loader == NULL) + if (d->Loader == NULL) { - this->Loader = new QUiLoader(); + d->Loader = new QUiLoader(); } - return this->Loader; + return d->Loader; } //----------------------------------------------------------------------------- ctkCmdLineModuleXslTransform* ctkCmdLineModuleFrontendQtGui::xslTransform() const { - if (this->Transform == NULL) + if (d->Transform == NULL) { - this->Transform = new ctkCmdLineModuleXslTransform(); + d->Transform = new ctkCmdLineModuleXslTransform(); } - return this->Transform; + return d->Transform; } //----------------------------------------------------------------------------- QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const { - if (Widget) return Widget; + if (d->Widget) return d->Widget; QBuffer input; input.setData(moduleReference().rawXmlDescription()); @@ -106,17 +125,17 @@ QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const uiLoader.addPluginPath(appPath + "/../designer"); } #endif - this->Widget = uiLoader->load(&uiForm); - return this->Widget; + d->Widget = uiLoader->load(&uiForm); + return d->Widget; } //----------------------------------------------------------------------------- QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter) const { - if (!this->Widget) return QVariant(); + if (!d->Widget) return QVariant(); - ctkCmdLineModuleObjectTreeWalker reader(this->Widget); + ctkCmdLineModuleObjectTreeWalker reader(d->Widget); while(reader.readNextParameter()) { if(reader.name() == parameter) @@ -131,9 +150,9 @@ QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter) const //----------------------------------------------------------------------------- void ctkCmdLineModuleFrontendQtGui::setValue(const QString ¶meter, const QVariant &value) { - if (!this->Widget) return; + if (!d->Widget) return; - ctkCmdLineModuleObjectTreeWalker walker(this->Widget); + ctkCmdLineModuleObjectTreeWalker walker(d->Widget); while(walker.readNextParameter()) { if(walker.name() == parameter && walker.value() != value) @@ -148,18 +167,18 @@ void ctkCmdLineModuleFrontendQtGui::setValue(const QString ¶meter, const QVa //----------------------------------------------------------------------------- QList ctkCmdLineModuleFrontendQtGui::parameterNames() const { - if (!ParameterNames.empty()) return ParameterNames; + if (!d->ParameterNames.empty()) return d->ParameterNames; // Compute the list of parameter names using the widget hierarchy // if it has already created (otherwise fall back to the superclass // implementation. // This avoids creating a ctkCmdLineModuleDescription instance. - if (this->Widget == 0) return ctkCmdLineModuleFrontend::parameterNames(); + if (d->Widget == 0) return ctkCmdLineModuleFrontend::parameterNames(); - ctkCmdLineModuleObjectTreeWalker walker(this->Widget); + ctkCmdLineModuleObjectTreeWalker walker(d->Widget); while(walker.readNextParameter()) { - ParameterNames.push_back(walker.name()); + d->ParameterNames.push_back(walker.name()); } - return ParameterNames; + return d->ParameterNames; } diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index 2e09989e3e..2f1a51b572 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -22,7 +22,9 @@ #ifndef CTKCMDLINEMODULEFRONTENDQTGUI_H #define CTKCMDLINEMODULEFRONTENDQTGUI_H -#include +#include "ctkCmdLineModuleFrontend.h" + +#include "ctkCommandLineModulesFrontendQtGuiExport.h" class ctkCmdLineModuleReference; class ctkCmdLineModuleXslTransform; @@ -30,7 +32,9 @@ class ctkCmdLineModuleXslTransform; class QUiLoader; class QWidget; -class ctkCmdLineModuleFrontendQtGui : public ctkCmdLineModuleFrontend +struct ctkCmdLineModuleFrontendQtGuiPrivate; + +class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCmdLineModuleFrontend { public: @@ -54,12 +58,8 @@ class ctkCmdLineModuleFrontendQtGui : public ctkCmdLineModuleFrontend private: - mutable QUiLoader* Loader; - mutable ctkCmdLineModuleXslTransform* Transform; - mutable QWidget* Widget; + QScopedPointer d; - // Cache the list of parameter names - mutable QList ParameterNames; }; #endif // CTKCMDLINEMODULEFRONTENDQTGUI_H diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt index 8da907bdfb..b2d20a05cb 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtWebKit/CMakeLists.txt @@ -16,6 +16,7 @@ set(KIT_export_directive "CTK_CMDLINEMODULEQTWEBKIT_EXPORT") set(KIT_SRCS ctkCmdLineModuleFrontendFactoryQtWebKit.cpp ctkCmdLineModuleFrontendQtWebKit.cpp + ctkCmdLineModuleFrontendQtWebKit_p.h ) # Headers that should run through moc diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp index 0bee4372fd..dabd4f238c 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.cpp @@ -21,9 +21,10 @@ #include "ctkCmdLineModuleFrontendFactoryQtWebKit.h" +#include "ctkCmdLineModuleFrontendQtWebKit_p.h" //---------------------------------------------------------------------------- -ctkCmdLineModuleFrontendQtWebKit *ctkCmdLineModuleFrontendFactoryQtWebKit::create(const ctkCmdLineModuleReference &moduleRef) +ctkCmdLineModuleFrontend* ctkCmdLineModuleFrontendFactoryQtWebKit::create(const ctkCmdLineModuleReference &moduleRef) { return new ctkCmdLineModuleFrontendQtWebKit(moduleRef); } diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h index 648a7220ec..3957941140 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h @@ -25,7 +25,6 @@ #include "ctkCommandLineModulesFrontendQtWebKitExport.h" #include "ctkCmdLineModuleFrontendFactory.h" -#include "ctkCmdLineModuleFrontendQtWebKit.h" class CTK_CMDLINEMODULEQTWEBKIT_EXPORT ctkCmdLineModuleFrontendFactoryQtWebKit : public ctkCmdLineModuleFrontendFactory { @@ -35,7 +34,7 @@ class CTK_CMDLINEMODULEQTWEBKIT_EXPORT ctkCmdLineModuleFrontendFactoryQtWebKit : virtual QString name() const; virtual QString description() const; - virtual ctkCmdLineModuleFrontendQtWebKit* create(const ctkCmdLineModuleReference& moduleRef); + virtual ctkCmdLineModuleFrontend* create(const ctkCmdLineModuleReference& moduleRef); }; #endif // CTKCMDLINEMODULEFRONTENDFACTORYQTWEBKIT_H diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp index 2cbc28bb8a..7c72de2224 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp @@ -19,7 +19,7 @@ =============================================================================*/ -#include "ctkCmdLineModuleFrontendQtWebKit.h" +#include "ctkCmdLineModuleFrontendQtWebKit_p.h" #include "ctkCmdLineModuleXslTransform.h" #include "ctkCmdLineModuleReference.h" diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h similarity index 100% rename from Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.h rename to Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h From 5a873cd5d5dfc7fb89ef0909a07ed901875339b3 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 01:35:03 +0200 Subject: [PATCH 125/247] Properly close the module explorer app when modules are still running. --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 52 +++++++++++++++++++ .../ctkCmdLineModuleExplorerMainWindow.h | 5 ++ .../ctkCmdLineModuleExplorerTabList.cpp | 5 ++ .../ctkCmdLineModuleExplorerTabList.h | 2 + 4 files changed, 64 insertions(+) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index 635e2241eb..7918734552 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -37,6 +37,9 @@ #include #include +#include +#include +#include #include @@ -116,6 +119,50 @@ void ctkCLModuleExplorerMainWindow::addModule(const QUrl &location) moduleManager.registerModule(location); } +void ctkCLModuleExplorerMainWindow::closeEvent(QCloseEvent *event) +{ + QList runningFrontends; + foreach (ctkCmdLineModuleFrontend* frontend, this->tabList->tabs()) + { + if (frontend->isRunning()) + { + runningFrontends << frontend; + } + } + + if (!runningFrontends.empty()) + { + QMessageBox::StandardButton button = + QMessageBox::warning(QApplication::topLevelWidgets().front(), + QString("Closing %1 running modules").arg(runningFrontends.size()), + "Some modules are still running.\n" + "Closing the application will cancel all current computations.", + QMessageBox::Ok | QMessageBox::Cancel); + if (button == QMessageBox::Ok) + { + QFutureSynchronizer futureSync; + futureSync.setCancelOnWait(true); + foreach(ctkCmdLineModuleFrontend* frontend, runningFrontends) + { + if (frontend->future().canCancel()) + { + futureSync.addFuture(frontend->future()); + } + } + futureSync.waitForFinished(); + event->accept(); + QMainWindow::closeEvent(event); + return; + } + else + { + event->ignore(); + return; + } + } + event->accept(); +} + void ctkCLModuleExplorerMainWindow::on_actionRun_triggered() { ctkCmdLineModuleFrontend* moduleFrontend = this->tabList->activeTab(); @@ -152,6 +199,11 @@ void ctkCLModuleExplorerMainWindow::on_actionOptions_triggered() settingsDialog->exec(); } +void ctkCLModuleExplorerMainWindow::on_actionQuit_triggered() +{ + this->close(); +} + void ctkCLModuleExplorerMainWindow::checkModulePaused() { if (this->currentFutureWatcher.future().isPaused()) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h index 481073f611..3c42a90320 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h @@ -50,12 +50,17 @@ class ctkCLModuleExplorerMainWindow : public QMainWindow void addModule(const QUrl &location); +protected: + + void closeEvent(QCloseEvent* event); + protected Q_SLOTS: void on_actionRun_triggered(); void on_actionPause_toggled(bool toggled); void on_actionCancel_triggered(); void on_actionOptions_triggered(); + void on_actionQuit_triggered(); void checkModulePaused(); void currentModuleResumed(); diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp index f5a6e8979f..2217671650 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp @@ -55,6 +55,11 @@ ctkCmdLineModuleFrontend* ctkCmdLineModuleExplorerTabList::activeTab() const return this->TabIndexToFrontend[index]; } +QList ctkCmdLineModuleExplorerTabList::tabs() const +{ + return this->TabIndexToFrontend; +} + void ctkCmdLineModuleExplorerTabList::addTab(ctkCmdLineModuleFrontend* moduleFrontend) { QWidget* widget = qobject_cast(moduleFrontend->guiHandle()); diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h index d2476cf72d..43f670e245 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h @@ -42,6 +42,8 @@ class ctkCmdLineModuleExplorerTabList : public QObject ctkCmdLineModuleFrontend* activeTab() const; + QList tabs() const; + Q_SLOT void addTab(ctkCmdLineModuleFrontend* frontend); Q_SIGNAL void tabActivated(ctkCmdLineModuleFrontend* module); From 37c5ca1e8cd297e4f54a7e78818dd43025cf840d Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 14:30:20 +0200 Subject: [PATCH 126/247] Added capability of providing different values for parameters using roles. --- .../Core/ctkCmdLineModuleFrontend.h | 30 +++++++++- .../QtGui/ctkCmdLineModuleFrontendQtGui.cpp | 58 ++++++++++--------- .../QtGui/ctkCmdLineModuleFrontendQtGui.h | 4 +- .../ctkCmdLineModuleObjectTreeWalker.cpp | 8 ++- .../ctkCmdLineModuleObjectTreeWalker_p.h | 3 +- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 3 +- 6 files changed, 72 insertions(+), 34 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 453d002dcb..62ee5d3083 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -42,11 +42,37 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject public: + enum ParameterValueRole { + + /* Data returned using this role must no be of any type not supported by + QVariant by default. For complex parameter types (like file, image, + geometry, etc.) the data must be convertible to a QString pointing + to a local resource. + */ + LocalResourceRole = 0, + + /* This role can be used in custom frontends to return a QVariant + containing for example an in-memory representation of a complex object. + One can then either convert the in-memory representation to a local + resource before running a module such that arbitrary backends relying on + the LocalResourceRole can process the data. Or one creates a custom + backend which knows how to handle QVariants returned by this role. + */ + UserRole = 8 + }; + + enum ParameterFilter { + Input = 0x01, + Output = 0x02, + All = Input | Output + }; + Q_DECLARE_FLAGS(ParameterFilters, ParameterFilter) + ~ctkCmdLineModuleFrontend(); virtual QObject* guiHandle() const = 0; - virtual QVariant value(const QString& parameter) const = 0; + virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const = 0; virtual void setValue(const QString& parameter, const QVariant& value) = 0; virtual ctkCmdLineModuleFuture future() const; @@ -82,4 +108,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject }; +Q_DECLARE_OPERATORS_FOR_FLAGS(ctkCmdLineModuleFrontend::ParameterFilters) + #endif // CTKCMDLINEMODULEFRONTEND_H diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index c4ad6a46ac..fb474cb8d1 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -38,19 +38,12 @@ struct ctkCmdLineModuleFrontendQtGuiPrivate { ctkCmdLineModuleFrontendQtGuiPrivate() - : Loader(NULL) - , Transform(NULL) - , Widget(NULL) + : Widget(NULL) {} - ~ctkCmdLineModuleFrontendQtGuiPrivate() - { - delete Loader; - delete Transform; - } - - mutable QUiLoader* Loader; - mutable ctkCmdLineModuleXslTransform* Transform; + mutable QScopedPointer Loader; + mutable QScopedPointer xslFile; + mutable QScopedPointer Transform; mutable QWidget* Widget; // Cache the list of parameter names @@ -76,9 +69,9 @@ QUiLoader* ctkCmdLineModuleFrontendQtGui::uiLoader() const { if (d->Loader == NULL) { - d->Loader = new QUiLoader(); + d->Loader.reset(new QUiLoader()); } - return d->Loader; + return d->Loader.data(); } @@ -87,9 +80,28 @@ ctkCmdLineModuleXslTransform* ctkCmdLineModuleFrontendQtGui::xslTransform() cons { if (d->Transform == NULL) { - d->Transform = new ctkCmdLineModuleXslTransform(); + d->Transform.reset(new ctkCmdLineModuleXslTransform()); + d->xslFile.reset(new QFile(":/ctkCmdLineModuleXmlToQtUi.xsl")); + d->Transform->setXslTransformation(d->xslFile.data()); } - return d->Transform; + return d->Transform.data(); +} + + +//----------------------------------------------------------------------------- +QVariant ctkCmdLineModuleFrontendQtGui::customValue(const QString& parameter, const QString& propertyName) const +{ + if (!d->Widget) return QVariant(); + + ctkCmdLineModuleObjectTreeWalker reader(d->Widget); + while(reader.readNextParameter()) + { + if(reader.name() == parameter) + { + return reader.value(propertyName); + } + } + return QVariant(); } @@ -108,8 +120,6 @@ QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const xslTransform->setInput(&input); xslTransform->setOutput(&uiForm); - QFile qtGuiTransformation(":/ctkCmdLineModuleXmlToQtUi.xsl"); - xslTransform->setXslTransformation(&qtGuiTransformation); if (!xslTransform->transform()) { // maybe throw an exception @@ -131,19 +141,11 @@ QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const //----------------------------------------------------------------------------- -QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter) const +QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter, int role) const { - if (!d->Widget) return QVariant(); + Q_UNUSED(role) - ctkCmdLineModuleObjectTreeWalker reader(d->Widget); - while(reader.readNextParameter()) - { - if(reader.name() == parameter) - { - return reader.value(); - } - } - return QVariant(); + return customValue(parameter); } diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index 2f1a51b572..dff60d8710 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -46,7 +46,7 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCm virtual QObject* guiHandle() const; - virtual QVariant value(const QString& parameter) const; + virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const; virtual void setValue(const QString& parameter, const QVariant& value); virtual QList parameterNames() const; @@ -56,6 +56,8 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCm virtual QUiLoader* uiLoader() const; virtual ctkCmdLineModuleXslTransform* xslTransform() const; + QVariant customValue(const QString& parameter, const QString& propertyName = QString()) const; + private: QScopedPointer d; diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp index 25e0117784..18244eeb17 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp @@ -105,9 +105,13 @@ QString ctkCmdLineModuleObjectTreeWalker::label() const } //---------------------------------------------------------------------------- -QVariant ctkCmdLineModuleObjectTreeWalker::value() const +QVariant ctkCmdLineModuleObjectTreeWalker::value(const QString &propertyName) const { - QString valProp = property("valueProperty").toString(); + QString valProp = propertyName; + if (valProp.isEmpty()) + { + valProp = property("valueProperty").toString(); + } return property(valProp); } diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h index a562a889b5..965d88e610 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h @@ -23,6 +23,7 @@ #define CTKCMDLINEMODULEOBJECTTREEWALKER_H #include +#include class QObject; class QVariant; @@ -57,7 +58,7 @@ class ctkCmdLineModuleObjectTreeWalker QString name() const; QString label() const; - QVariant value() const; + QVariant value(const QString& propertyName = QString()) const; void setValue(const QVariant& value); diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index 41040df6af..dfca7bcd46 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -53,8 +53,9 @@ class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFac virtual QObject* guiHandle() const { return NULL; } - virtual QVariant value(const QString& parameter) const + virtual QVariant value(const QString& parameter, int role) const { + Q_UNUSED(role) QVariant value = currentValues[parameter]; if (!value.isValid()) return this->moduleReference().description().parameter(parameter).defaultValue(); From 9bd490aab46b6260ccee3f02f7dcc338def2baf5 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 14:31:55 +0200 Subject: [PATCH 127/247] Enhanced to function pointer backend to handle custom parameter types. --- .../ctkCmdLineModuleBackendFPTypeTraits.h | 31 +++++++ .../ctkCmdLineModuleBackendFPUtil_p.h | 6 +- ...ctkCmdLineModuleBackendFunctionPointer.cpp | 14 +++- .../ctkCmdLineModuleBackendFunctionPointer.h | 84 ++++++++++++++----- 4 files changed, 113 insertions(+), 22 deletions(-) diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h index 7f27f25256..dd779e6e4b 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPTypeTraits.h @@ -86,6 +86,37 @@ class TypeTraits typename Select::Result, typename UnConst::Result>::Result >::Result RawType; }; +template +struct EnableIf +{ + typedef T Type; +}; + +template +struct EnableIf {}; + +template +struct IsSame +{ + static bool const value = false; +}; + +template +struct IsSame +{ + static bool const value = true; +}; + +template +struct IsBaseOf +{ + static D* MakeD(); + static char (& Test(B*))[1]; + static char (& Test(...))[2]; + static bool const value = sizeof Test(MakeD()) == 1 && + !IsSame::value; +}; + } } diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h index c0e5fce717..f0d20e685a 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFPUtil_p.h @@ -22,6 +22,8 @@ #ifndef CTKCMDLINEMODULEBACKENDFPUTIL_P_H #define CTKCMDLINEMODULEBACKENDFPUTIL_P_H +#include "ctkCommandLineModulesBackendFunctionPointerExport.h" + #include class ctkCmdLineModuleBackendFunctionPointer; @@ -29,7 +31,7 @@ class ctkCmdLineModuleBackendFunctionPointer; namespace ctk { namespace CmdLineModuleBackendFunctionPointer { -struct FunctionPointerHolderBase +struct CTK_CMDLINEMODULEBACKENDFP_EXPORT FunctionPointerHolderBase { virtual ~FunctionPointerHolderBase(); @@ -84,7 +86,7 @@ struct FunctionPointerHolder2 : public FunctionPointerHolderBase FunctionPointerType Fp; }; -struct FunctionPointerProxy +struct CTK_CMDLINEMODULEBACKENDFP_EXPORT FunctionPointerProxy { FunctionPointerProxy(); ~FunctionPointerProxy(); diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp index eae779baeb..4e3d7231ec 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp @@ -176,6 +176,11 @@ ctkCmdLineModuleBackendFunctionPointer::ctkCmdLineModuleBackendFunctionPointer() this->registerFunctionPointer("Fibonacci Number", CalculateFibonacciNumbers, "Count"); } +//---------------------------------------------------------------------------- +ctkCmdLineModuleBackendFunctionPointer::~ctkCmdLineModuleBackendFunctionPointer() +{ +} + //---------------------------------------------------------------------------- QString ctkCmdLineModuleBackendFunctionPointer::name() const { @@ -206,6 +211,7 @@ qint64 ctkCmdLineModuleBackendFunctionPointer::timeStamp(const QUrl &location) c QByteArray ctkCmdLineModuleBackendFunctionPointer::rawXmlDescription(const QUrl& location) { if (!d->UrlToFpDescription.contains(location)) return QByteArray(); + qDebug() << d->UrlToFpDescription[location].d->xmlDescription(); return QByteArray(qPrintable(d->UrlToFpDescription[location].d->xmlDescription())); } @@ -215,7 +221,7 @@ ctkCmdLineModuleFuture ctkCmdLineModuleBackendFunctionPointer::run(ctkCmdLineMod QUrl url = frontend->location(); const Description& descr = d->UrlToFpDescription[url]; - QList args = frontend->values().values(); + QList args = this->arguments(frontend); // Instances of ctkCmdLineModuleFunctionPointerTask are auto-deleted by the // thread pool @@ -223,6 +229,12 @@ ctkCmdLineModuleFuture ctkCmdLineModuleBackendFunctionPointer::run(ctkCmdLineMod return fpTask->start(); } +//---------------------------------------------------------------------------- +QList ctkCmdLineModuleBackendFunctionPointer::arguments(ctkCmdLineModuleFrontend *frontend) const +{ + return frontend->values().values(); +} + //---------------------------------------------------------------------------- QList ctkCmdLineModuleBackendFunctionPointer::registeredFunctionPointers() const { diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h index 38e05e7a2c..7e111d979f 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h @@ -26,6 +26,7 @@ #include "ctkCommandLineModulesBackendFunctionPointerExport.h" #include "ctkCmdLineModuleBackendFPTypeTraits.h" +#include "ctkCmdLineModuleBackendFPUtil_p.h" #include #include @@ -44,6 +45,45 @@ struct FunctionPointerProxy; template QString GetParameterTypeName(); +struct ImageType {}; + +// default parameter description +template +struct CreateXmlFor +{ + static QString parameter(int index, const QString& typeName, const QString& label = QString(), const QString& description = QString()) + { + QString xmlParameter; + QTextStream str(&xmlParameter); + str << " <" << typeName << ">\n"; + str << " " << QString("param%1").arg(index) << "\n"; + str << " " << index << "\n"; + str << " " << (description.isEmpty() ? "Description not available." : description) << "\n"; + str << " \n"; + str << " \n"; + return xmlParameter; + } +}; + +// specialization for input image types +template +struct CreateXmlFor::value >::Type > +{ + static QString parameter(int index, const QString& typeName, const QString& label = QString(), const QString& description = QString()) + { + QString xmlParameter; + QTextStream str(&xmlParameter); + str << " <" << typeName << ">\n"; + str << " " << QString("param%1").arg(index) << "\n"; + str << " " << index << "\n"; + str << " " << (description.isEmpty() ? "Description not available." : description) << "\n"; + str << " \n"; + str << " input\n"; + str << " \n"; + return xmlParameter; + } +}; + } } @@ -93,6 +133,7 @@ class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : }; ctkCmdLineModuleBackendFunctionPointer(); + ~ctkCmdLineModuleBackendFunctionPointer(); virtual QString name() const; virtual QString description() const; @@ -103,16 +144,19 @@ class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : virtual QByteArray rawXmlDescription(const QUrl& location); - virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend *frontend); - QList registeredFunctionPointers() const; template Description* registerFunctionPointer(const QString& title, void (*fp)(A), const QString& paramLabel = QString(), const QString& paramDescr = QString()) { + typedef typename ctk::CmdLineModuleBackendFunctionPointer::TypeTraits
::RawType RawTypeA; + QList params; - params << CreateXmlForParameter(0, paramLabel, paramDescr); + params << ctk::CmdLineModuleBackendFunctionPointer::CreateXmlFor:: + parameter(0, + ctk::CmdLineModuleBackendFunctionPointer::GetParameterTypeName(), + paramLabel, paramDescr); return this->registerFunctionPointerProxy(title, ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy(fp), params); } @@ -121,35 +165,37 @@ class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : const QString& paramLabel0 = QString(), const QString& paramDescr0 = QString(), const QString& paramLabel1 = QString(), const QString& paramDescr1 = QString()) { + typedef typename ctk::CmdLineModuleBackendFunctionPointer::TypeTraits::RawType RawTypeA; + typedef typename ctk::CmdLineModuleBackendFunctionPointer::TypeTraits::RawType RawTypeB; + QList params; - params << CreateXmlForParameter(0, paramLabel0, paramDescr0); - params << CreateXmlForParameter(1, paramLabel1, paramDescr1); + params << ctk::CmdLineModuleBackendFunctionPointer::CreateXmlFor:: + parameter(0, + ctk::CmdLineModuleBackendFunctionPointer::GetParameterTypeName(), + paramLabel0, paramDescr0); + params << ctk::CmdLineModuleBackendFunctionPointer::CreateXmlFor:: + parameter(1, + ctk::CmdLineModuleBackendFunctionPointer::GetParameterTypeName(), + paramLabel1, paramDescr1); return this->registerFunctionPointerProxy(title, ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy(fp), params); } +protected: + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend); + + virtual QList arguments(ctkCmdLineModuleFrontend* frontend) const; + private: Description* registerFunctionPointerProxy(const QString &title, const ctk::CmdLineModuleBackendFunctionPointer::FunctionPointerProxy& proxy, const QList& params); - template - QString CreateXmlForParameter(int index, const QString& label = QString(), const QString& description = QString()) - { - QString xmlParameter; - QTextStream str(&xmlParameter); - QString typeName = ctk::CmdLineModuleBackendFunctionPointer::GetParameterTypeName::RawType>(); - str << " <" << typeName << ">\n"; - str << " " << QString("param%1").arg(index) << "\n"; - str << " " << index << "\n"; - str << " " << (description.isEmpty() ? "Description not available." : description) << "\n"; - str << " \n"; - str << " \n"; - return xmlParameter; - } QScopedPointer d; }; + #endif // CTKCMDLINEMODULEBACKENDFUNCTIONPOINTER_H From 21f0d8497fda5e345fac6073a255067cab0d6251 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 14:32:35 +0200 Subject: [PATCH 128/247] Added convenience methods for retrieving and resetting parameters. --- .../Core/ctkCmdLineModuleFrontend.cpp | 38 +++++++++++++++++++ .../Core/ctkCmdLineModuleFrontend.h | 7 ++++ 2 files changed, 45 insertions(+) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp index 68d882335a..baa39cde28 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp @@ -128,3 +128,41 @@ void ctkCmdLineModuleFrontend::setValues(const QHash &values) setValue(iter.key(), iter.value()); } } + +//---------------------------------------------------------------------------- +QList ctkCmdLineModuleFrontend::parameters(const QString &type, ParameterFilters filters) +{ + ctkCmdLineModuleDescription description = this->moduleReference().description(); + QList parameters; + foreach(ctkCmdLineModuleParameterGroup group, description.parameterGroups()) + { + foreach(ctkCmdLineModuleParameter param, group.parameters()) + { + if (filters.testFlag(Input) && + (param.channel().isEmpty() || param.channel().compare("input", Qt::CaseInsensitive))) + { + if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive)) + { + parameters << param; + } + } + if (filters.testFlag(Output) && param.channel().compare("output", Qt::CaseInsensitive)) + { + if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive)) + { + parameters << param; + } + } + } + } + return parameters; +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontend::resetValues() +{ + foreach(ctkCmdLineModuleParameter param, this->parameters()) + { + this->setValue(param.name(), param.defaultValue()); + } +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 62ee5d3083..ac52d6d557 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -31,6 +31,7 @@ class QUrl; class ctkCmdLineModuleFuture; class ctkCmdLineModuleReference; +class ctkCmdLineModuleParameter; class ctkCmdLineModuleFrontendPrivate; /** @@ -91,6 +92,12 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value); + // convenience methods + + QList parameters(const QString& type = QString(), ParameterFilters filters = All); + + void resetValues(); + protected: ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef); From 54428f500fb318f9df13a646b26b9d1598a27f94 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 14:33:29 +0200 Subject: [PATCH 129/247] Added test for verifying customizability of the Qt Gui frontend. --- .../Testing/Cpp/CMakeLists.txt | 55 +++- .../Testing/Cpp/MyImageComboBoxTest.xsl | 63 +++++ .../ctkCmdLineModuleQtCustomizationTest.cpp | 255 ++++++++++++++++++ .../Cpp/ctkCmdLineModuleTestResources.qrc | 5 + 4 files changed, 369 insertions(+), 9 deletions(-) create mode 100644 Libs/CommandLineModules/Testing/Cpp/MyImageComboBoxTest.xsl create mode 100644 Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp create mode 100644 Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleTestResources.qrc diff --git a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt index 7e751e003d..e98d39d579 100644 --- a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt @@ -1,9 +1,24 @@ set(KIT CTKCommandLineModules) set(LIBRARY_NAME ${KIT}) -create_test_sourcelist(Tests ${KIT}CppTests.cpp - ctkCmdLineModuleFutureTest.cpp - ) +set(_test_srcs) + +if(CTK_LIB_CommandLineModules/Frontend/QtGui) + set(QT_USE_QTUITOOLS 1) + include(${QT_USE_FILE}) + + if(CTK_LIB_CommandLineModules/Backend/LocalProcess) + list(APPEND _test_srcs ctkCmdLineModuleFutureTest.cpp) + endif() + if(CTK_LIB_CommandLineModules/Backend/FunctionPointer) + list(APPEND _test_srcs ctkCmdLineModuleQtCustomizationTest.cpp) + QT4_GENERATE_MOCS( + ctkCmdLineModuleQtCustomizationTest.cpp + ) + endif() +endif() + +create_test_sourcelist(Tests ${KIT}CppTests.cpp ${_test_srcs}) set(TestsToRun ${Tests}) remove(TestsToRun ${KIT}CppTests.cpp) @@ -14,6 +29,9 @@ set(Tests_SRCS ${Tests_SRCS} set(Tests_MOC_SRCS ${Tests_MOC_SRCS} ctkCmdLineModuleSignalTester.h ) +set(Tests_RESOURCES + ctkCmdLineModuleTestResources.qrc +) set(_base_src_include_dir ${CMAKE_SOURCE_DIR}/Libs/CommandLineModules) set(_base_bin_include_dir ${CMAKE_BINARY_DIR}/Libs/CommandLineModules) @@ -23,13 +41,30 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${_base_src_include_dir}/Core ${_base_bin_include_dir}/Core - ${_base_src_include_dir}/Backend/LocalProcess - ${_base_bin_include_dir}/Backend/LocalProcess ) +set(_additional_link_libraries) + +if(CTK_LIB_CommandLineModules/Backend/LocalProcess) + include_directories(${_base_src_include_dir}/Backend/LocalProcess + ${_base_bin_include_dir}/Backend/LocalProcess) + list(APPEND _additional_link_libraries CTKCommandLineModulesBackendLocalProcess) +endif() + +if(CTK_LIB_CommandLineModules/Backend/FunctionPointer) + include_directories(${_base_src_include_dir}/Backend/FunctionPointer + ${_base_bin_include_dir}/Backend/FunctionPointer) + list(APPEND _additional_link_libraries CTKCommandLineModulesBackendFunctionPointer) +endif() + +if(CTK_LIB_CommandLineModules/Frontend/QtGui) + include_directories(${_base_src_include_dir}/Frontend/QtGui + ${_base_bin_include_dir}/Frontend/QtGui) + list(APPEND _additional_link_libraries CTKCommandLineModulesFrontendQtGui) +endif() + set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) - set(Tests_UI_CPP) if(TEST_UI_FORMS) QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) @@ -38,7 +73,7 @@ set(Tests_RESOURCES_SRCS) QT4_ADD_RESOURCES(Tests_RESOURCES_SRCS ${Tests_RESOURCES}) add_executable(${KIT}CppTests ${Tests} ${Tests_SRCS} ${Tests_MOC_CPP} ${Tests_UI_CPP} ${Tests_RESOURCES_SRCS}) -target_link_libraries(${KIT}CppTests CTKCommandLineModulesBackendLocalProcess) +target_link_libraries(${KIT}CppTests ${_additional_link_libraries}) add_dependencies(${KIT}CppTests ctkCmdLineTestModules) if(TARGET CTKCommandLineModulesCoreCppTests) @@ -52,5 +87,7 @@ endif() # Add Tests # -SIMPLE_TEST(ctkCmdLineModuleFutureTest) - +foreach(_src ${_test_srcs}) + get_filename_component(_test_name ${_src} NAME_WE) + SIMPLE_TEST(${_test_name}) +endforeach() diff --git a/Libs/CommandLineModules/Testing/Cpp/MyImageComboBoxTest.xsl b/Libs/CommandLineModules/Testing/Cpp/MyImageComboBoxTest.xsl new file mode 100644 index 0000000000..57ffb333c1 --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/MyImageComboBoxTest.xsl @@ -0,0 +1,63 @@ + + + + + + + + + + + + + currentValue + + + + + + + + + + + ctkPathLineEdit::Files + + + + + + + Browse... + + + + + + + + + + + + + + + BrowseButton + clicked() + parameter: + browse() + + + + diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp new file mode 100644 index 0000000000..8bf73b34e9 --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp @@ -0,0 +1,255 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + +=========================================================================*/ + +// Qt includes +#include +#include +#include +#include +#include + +// CTK includes +#include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleFrontendQtGui.h" +#include "ctkCmdLineModuleBackendFunctionPointer.h" +#include "ctkCmdLineModuleParameter.h" +#include "ctkCmdLineModuleParameterGroup.h" +#include "ctkCmdLineModuleDescription.h" +#include "ctkCmdLineModuleXslTransform.h" +#include "ctkCmdLineModuleFuture.h" + +#include "ctkTest.h" + +// ---------------------------------------------------------------------------- +struct MyImageData : public ctk::CmdLineModuleBackendFunctionPointer::ImageType +{ + MyImageData(const QString& path = QString()) + : Path(path) + {} + + QString Path; +}; + +Q_DECLARE_METATYPE(MyImageData) +Q_DECLARE_METATYPE(const MyImageData*) + +// ---------------------------------------------------------------------------- +namespace ctk { +namespace CmdLineModuleBackendFunctionPointer { + +template<> +QString GetParameterTypeName() +{ + return "image"; +} + +}} + +// ---------------------------------------------------------------------------- +class MyImageComboBox : public QComboBox +{ + Q_OBJECT + +public: + + Q_PROPERTY(QString currentValue READ currentValue WRITE setCurrentValue) + Q_PROPERTY(const MyImageData* currentImage READ currentImage) + + MyImageComboBox(QWidget* parent = 0) + : QComboBox(parent) + { + imageData << MyImageData("/path/to/image1") + << MyImageData("/path/to/image2") + << MyImageData("/path/to/image3"); + + this->addItem("Image 1"); + this->addItem("Image 2"); + this->addItem("Image 3"); + } + + QString currentValue() const + { + return this->imageData.at(this->currentIndex()).Path; + } + + void setCurrentValue(const QString& path) + { + this->imageData[this->currentIndex()].Path = path; + } + + const MyImageData* currentImage() const + { + return &this->imageData.at(this->currentIndex()); + } + +private: + + QList imageData; +}; + + +// ---------------------------------------------------------------------------- +class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui +{ +public: + MyQtGuiFrontend(const ctkCmdLineModuleReference& moduleRef) + : ctkCmdLineModuleFrontendQtGui(moduleRef) + {} + + QUiLoader* uiLoader() const + { + struct MyUiLoader : public QUiLoader { + QStringList availableWidgets() const + { + return QUiLoader::availableWidgets() << "MyImageComboBox"; + } + QWidget* createWidget(const QString& className, QWidget* parent, const QString& name) + { + if (className == "MyImageComboBox") + { + MyImageComboBox* comboBox = new MyImageComboBox(parent); + comboBox->setObjectName(name); + comboBox->setCurrentIndex(1); + return comboBox; + } + return QUiLoader::createWidget(className, parent, name); + } + }; + static MyUiLoader myUiLoader; + return &myUiLoader; + } + + ctkCmdLineModuleXslTransform* xslTransform() const + { + static bool initialized = false; + ctkCmdLineModuleXslTransform* transform = ctkCmdLineModuleFrontendQtGui::xslTransform(); + if (!initialized) + { + transform->bindVariable("imageInputWidget", "MyImageComboBox"); + static QFile extraXsl(":/MyImageComboBoxTest.xsl"); + transform->setXslExtraTransformation(&extraXsl); + initialized = true; + } + return transform; + } + + QVariant value(const QString ¶meter, int role) const + { + if (role == UserRole) + { + ctkCmdLineModuleParameter param = this->moduleReference().description().parameter(parameter); + if (param.channel() == "input" && param.tag() == "image") + { + return this->customValue(parameter, "currentImage"); + } + return QVariant(); + } + return ctkCmdLineModuleFrontendQtGui::value(parameter, role); + } +}; + +// ---------------------------------------------------------------------------- +class MyFpBackend : public ctkCmdLineModuleBackendFunctionPointer +{ + +protected: + + QList arguments(ctkCmdLineModuleFrontend *frontend) const + { + QList args; + foreach(ctkCmdLineModuleParameter param, frontend->parameters()) + { + QVariant arg = frontend->value(param.name(), ctkCmdLineModuleFrontend::UserRole); + if (!arg.isValid()) + { + arg = frontend->value(param.name()); + } + args << arg; + } + + return args; + } +}; + +// ---------------------------------------------------------------------------- +QString CustomImageDataPath; +void CustomImageTypeModule(const MyImageData* imageData) +{ + CustomImageDataPath = imageData->Path; +} + +// ---------------------------------------------------------------------------- +class ctkCmdLineModuleQtCustomizationTester: public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void testCustomization(); + +}; + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleQtCustomizationTester::testCustomization() +{ + qRegisterMetaType("const MyImageData*"); + + ctkCmdLineModuleManager moduleManager; + + MyFpBackend fpBackend; + fpBackend.registerFunctionPointer("Image Type Customization", CustomImageTypeModule); + + moduleManager.registerBackend(&fpBackend); + QUrl url = fpBackend.registeredFunctionPointers().front(); + moduleManager.registerModule(url); + + ctkCmdLineModuleReference moduleRef = moduleManager.moduleReference(url); + + ctkCmdLineModuleFrontend* fpFrontend = new MyQtGuiFrontend(moduleRef); + // force the creation of the frontend gui + fpFrontend->guiHandle(); + + QString expectedImageValue = "/path/to/image2"; + QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue); + + // get a custom QVariant value holding the custom widget + QCOMPARE(fpFrontend->value("param0", ctkCmdLineModuleFrontend::UserRole).value()->Path, + expectedImageValue); + + // now set the property for the "LocalResourceRole" (the default property) to something else + expectedImageValue = "/tmp/path/to/image2"; + fpFrontend->setValue("param0", expectedImageValue); + QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue); + + QVERIFY(CustomImageDataPath.isEmpty()); + + // run the module (function pointer) and check that is gets the tmp path + ctkCmdLineModuleFuture future = moduleManager.run(fpFrontend); + sleep(1); + QApplication::processEvents(); + future.waitForFinished(); + + QCOMPARE(CustomImageDataPath, expectedImageValue); +} + + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleQtCustomizationTest) +#include "moc_ctkCmdLineModuleQtCustomizationTest.cpp" diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleTestResources.qrc b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleTestResources.qrc new file mode 100644 index 0000000000..71b03099a6 --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleTestResources.qrc @@ -0,0 +1,5 @@ + + + MyImageComboBoxTest.xsl + + From f3c159bed6f5b7e3585fcf96e0336870fb8ce030 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 14:33:48 +0200 Subject: [PATCH 130/247] Added reset functionality to the explorer app. --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 7 +++++++ .../ctkCmdLineModuleExplorerMainWindow.h | 2 ++ .../ctkCmdLineModuleExplorerMainWindow.ui | 11 +++++++++++ 3 files changed, 20 insertions(+) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index 7918734552..343b5c3309 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -204,6 +204,11 @@ void ctkCLModuleExplorerMainWindow::on_actionQuit_triggered() this->close(); } +void ctkCLModuleExplorerMainWindow::on_actionReset_triggered() +{ + this->tabList->activeTab()->resetValues(); +} + void ctkCLModuleExplorerMainWindow::checkModulePaused() { if (this->currentFutureWatcher.future().isPaused()) @@ -266,6 +271,7 @@ void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend ui->actionRun->setEnabled(false); ui->actionPause->setEnabled(false); ui->actionCancel->setEnabled(false); + ui->actionReset->setEnabled(false); currentFutureWatcher.setFuture(ctkCmdLineModuleFuture()); } else @@ -274,6 +280,7 @@ void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend ui->actionPause->setEnabled(module->future().canPause() && module->isRunning()); ui->actionPause->setChecked(module->isPaused()); ui->actionCancel->setEnabled(module->future().canCancel() && module->isRunning()); + ui->actionReset->setEnabled(true); currentFutureWatcher.setFuture(module->future()); } } diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h index 3c42a90320..1a1542a4c8 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h @@ -62,6 +62,8 @@ protected Q_SLOTS: void on_actionOptions_triggered(); void on_actionQuit_triggered(); + void on_actionReset_triggered(); + void checkModulePaused(); void currentModuleResumed(); void currentModuleCanceled(); diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui index 5465123117..6a856007ba 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui @@ -63,6 +63,7 @@ +
@@ -83,6 +84,8 @@ + +
@@ -225,6 +228,14 @@ &Options... + + + Reset + + + Reset to default values + + From a7ce94067755be5fed3f4220e200ce575d7c2d09 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 16:07:45 +0200 Subject: [PATCH 131/247] Fixed some Windows warnings and compiler errors. --- .../ctkCmdLineModuleExplorerProgressWidget.h | 2 +- .../ctkCmdLineModuleExplorerTreeWidget.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h | 4 ++-- Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h | 2 +- .../Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp | 2 +- .../Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp | 3 ++- .../Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h | 2 +- .../Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp | 2 +- 14 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h index 37e76613c5..c22358d87e 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h @@ -22,13 +22,13 @@ #ifndef CTKCMDLINEMODULEEXPLORERPROGRESSWIDGET_H #define CTKCMDLINEMODULEEXPLORERPROGRESSWIDGET_H +#include "ctkCmdLineModuleResult.h" #include #include #include class ctkCmdLineModuleFuture; -class ctkCmdLineModuleResult; namespace Ui { class ctkCmdLineModuleExplorerProgressWidget; diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h index 9470708250..7b0c9c39b1 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h @@ -27,7 +27,7 @@ #include class ctkCmdLineModuleFrontend; -class ctkCmdLineModuleFrontendFactory; +struct ctkCmdLineModuleFrontendFactory; class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h index 84c1f0fd6f..0338a3279a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h @@ -24,7 +24,7 @@ #include -class ctkCmdLineModuleCachePrivate; +struct ctkCmdLineModuleCachePrivate; class QUrl; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h index 6d8bdef16c..00d9e86c9d 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h @@ -84,7 +84,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDescription private: friend class ctkCmdLineModuleXmlParser; - friend class ctkCmdLineModuleReferencePrivate; + friend struct ctkCmdLineModuleReferencePrivate; ctkCmdLineModuleDescription(); diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index ac52d6d557..3551007328 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -32,7 +32,7 @@ class QUrl; class ctkCmdLineModuleFuture; class ctkCmdLineModuleReference; class ctkCmdLineModuleParameter; -class ctkCmdLineModuleFrontendPrivate; +struct ctkCmdLineModuleFrontendPrivate; /** * \ingroup CommandLineModulesCore diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h index 9e34237444..209f9c7625 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h @@ -33,7 +33,7 @@ struct ctkCmdLineModuleFrontendFactory; class ctkCmdLineModuleFrontend; class ctkCmdLineModuleFuture; -class ctkCmdLineModuleManagerPrivate; +struct ctkCmdLineModuleManagerPrivate; /** * \ingroup CommandLineModulesCore diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h index 2a6fb7fb07..8bbd5170ec 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h @@ -28,7 +28,7 @@ class QTextStream; class QStringList; -class ctkCmdLineModuleParameterPrivate; +struct ctkCmdLineModuleParameterPrivate; /** * \ingroup CommandLineModulesCore @@ -125,7 +125,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameter private: - friend class ctkCmdLineModuleParameterParser; + friend struct ctkCmdLineModuleParameterParser; friend class ctkCmdLineModuleXmlParser; ctkCmdLineModuleParameter(); diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h index a4979620b3..0d0669c677 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h @@ -29,7 +29,7 @@ class QTextStream; class ctkCmdLineModuleParameter; -class ctkCmdLineModuleParameterGroupPrivate; +struct ctkCmdLineModuleParameterGroupPrivate; /** * \ingroup CommandLineModulesCore diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index ce3f2bb906..55548948ff 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -29,7 +29,7 @@ struct ctkCmdLineModuleBackend; class ctkCmdLineModuleDescription; -class ctkCmdLineModuleReferencePrivate; +struct ctkCmdLineModuleReferencePrivate; /** * \ingroup CommandLineModulesCore diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h index af252e9d14..175da1fc8f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h @@ -27,7 +27,7 @@ class ctkCmdLineModuleDescription; class ctkCmdLineModuleParameter; -class ctkCmdLineModuleParameterParser; +struct ctkCmdLineModuleParameterParser; class QIODevice; diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index fb474cb8d1..752f4d17fa 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -132,7 +132,7 @@ QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const QString appPath = QCoreApplication::applicationDirPath(); if (appPath.endsWith(CMAKE_INTDIR)) { - uiLoader.addPluginPath(appPath + "/../designer"); + uiLoader->addPluginPath(appPath + "/../designer"); } #endif d->Widget = uiLoader->load(&uiForm); diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp index 7c72de2224..b4fa195af1 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp @@ -68,8 +68,9 @@ QObject* ctkCmdLineModuleFrontendQtWebKit::guiHandle() const } //---------------------------------------------------------------------------- -QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter) const +QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter, int role) const { + Q_UNUSED(role) QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]"); if (webElement.isNull()) return QVariant(); // Work around bug https://bugs.webkit.org/show_bug.cgi?id=32865 for input elements diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h index 5e9fbbe683..551ed8991b 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h @@ -37,7 +37,7 @@ class ctkCmdLineModuleFrontendQtWebKit : public ctkCmdLineModuleFrontend virtual QObject* guiHandle() const; - virtual QVariant value(const QString& parameter) const; + virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const; virtual void setValue(const QString& parameter, const QVariant& value); //virtual QList parameterNames() const; diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp index 8bf73b34e9..e3e71f89ed 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp @@ -242,7 +242,7 @@ void ctkCmdLineModuleQtCustomizationTester::testCustomization() // run the module (function pointer) and check that is gets the tmp path ctkCmdLineModuleFuture future = moduleManager.run(fpFrontend); - sleep(1); + QTest::qSleep(500); QApplication::processEvents(); future.waitForFinished(); From bf1d4584a2081e48fd9e175ffab088df582d07da Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 21 Aug 2012 16:18:27 +0200 Subject: [PATCH 132/247] Fixed sleeping function usage on Windows. --- ...ctkCmdLineModuleBackendFunctionPointer.cpp | 22 ++++++++++++++-- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 25 +++++++++++++++--- .../TestBed/ctkCmdLineModuleTestBed.cpp | 26 ++++++++++++++----- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp index 4e3d7231ec..dd409ee590 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.cpp @@ -34,6 +34,7 @@ #include #include + namespace ctk { namespace CmdLineModuleBackendFunctionPointer { @@ -55,12 +56,29 @@ CTK_CMDLINEMODULEBACKENDFP_EXPORT QString GetParameterTypeName >() } //---------------------------------------------------------------------------- +#ifdef Q_OS_WIN +#include +void sleep_secs(int secs) +{ + Sleep(secs*1000); +} +#else +#include +void sleep_secs(int secs) +{ + struct timespec nanostep; + nanostep.tv_sec = secs; + nanostep.tv_nsec = 0; + nanosleep(&nanostep, NULL); +} +#endif + void CalculateFibonacciNumbers(int level) //, QList* result) { qDebug() << "Number: 0"; if (level > 0) { - sleep(1); + sleep_secs(1); qDebug() << "Number: 1"; if (level == 1) return; } @@ -72,7 +90,7 @@ void CalculateFibonacciNumbers(int level) //, QList* result) int tmp = first; first = second; second = first + tmp; - sleep(1); + sleep_secs(1); qDebug() << "Number:" << second; } } diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index dfca7bcd46..dfb74e3c58 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -40,6 +40,24 @@ #include +#ifdef Q_OS_WIN +#include +#else +#include +#endif + +void sleep_ms(int ms) +{ +#ifdef Q_OS_WIN + Sleep(ms); +#else + struct timespec nanostep; + nanostep.tv_sec = ms / 1000; + nanostep.tv_nsec = ((ms % 1000) * 1000.0 * 1000.0); + nanosleep(&nanostep, NULL); +#endif +} + class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFactory { public: @@ -189,17 +207,18 @@ bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModule expectedSignals.push_back("module.resumed"); expectedSignals.push_back("module.paused"); } + if (future.canCancel()) { expectedSignals.push_back("module.canceled"); } expectedSignals.push_back("module.finished"); - sleep(1); + sleep_ms(500); QCoreApplication::processEvents(); future.pause(); - sleep(1); + sleep_ms(500); QCoreApplication::processEvents(); if (future.canPause()) @@ -218,7 +237,7 @@ bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModule future.togglePaused(); QCoreApplication::processEvents(); - sleep(1); + sleep_ms(500); if (future.isPaused() && future.isRunning()) { diff --git a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp index 6e1dae8314..5337896525 100644 --- a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp +++ b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp @@ -28,7 +28,24 @@ #include #include + +#ifdef Q_OS_WIN +#include +#else #include +#endif + +void sleep_ms(int ms) +{ +#ifdef Q_OS_WIN + Sleep(ms); +#else + struct timespec nanostep; + nanostep.tv_sec = static_cast(ms / 1000); + nanostep.tv_nsec = ((ms % 1000) * 1000.0 * 1000.0); + nanosleep(&nanostep, NULL); +#endif +} int main(int argc, char* argv[]) { @@ -98,8 +115,6 @@ int main(int argc, char* argv[]) QTime time; time.start(); - struct timespec nanostep; - if (!outputs.empty()) { out << "\n"; @@ -132,10 +147,7 @@ int main(int argc, char* argv[]) } // simulate some work - nanostep.tv_sec = static_cast(stepTime); - double millisecs = (stepTime - static_cast(stepTime)) * 1000.0; - nanostep.tv_nsec = static_cast(millisecs * 1000.0 * 1000.0); - nanosleep(&nanostep, NULL); + sleep_ms(stepTime*1000); // print the first output if (output != "dummy") @@ -147,7 +159,7 @@ int main(int argc, char* argv[]) } // sleep 1 second to avoid squashing the last progress event with the finished event - sleep(1); + sleep_ms(1000); if (exitCrash) { From fad36e7ea1468f69a8b524e8e78340aff73ebac6 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Wed, 22 Aug 2012 08:32:59 +0100 Subject: [PATCH 133/247] Added class level doxygen for command line modules --- ...tkCmdLineModuleExplorerDirectorySettings.h | 4 + .../ctkCmdLineModuleExplorerMainWindow.h | 5 +- .../ctkCmdLineModuleExplorerProgressWidget.h | 4 + .../ctkCmdLineModuleExplorerTabList.h | 4 + .../ctkCmdLineModuleExplorerTreeWidget.h | 4 + .../ctkCmdLineModuleBackendFunctionPointer.h | 5 ++ .../ctkCmdLineModuleFunctionPointerTask_p.h | 6 ++ .../ctkCmdLineModuleBackendLocalProcess.h | 6 ++ .../ctkCmdLineModuleProcessTask.h | 6 ++ .../ctkCmdLineModuleProcessWatcher_p.h | 5 ++ .../Core/ctkCmdLineModuleBackend.h | 34 +++++++- .../Core/ctkCmdLineModuleCache_p.h | 35 ++++++++ .../ctkCmdLineModuleDefaultPathBuilder.cpp | 3 +- .../Core/ctkCmdLineModuleDefaultPathBuilder.h | 38 +++++++-- .../Core/ctkCmdLineModuleDescription.h | 4 +- .../Core/ctkCmdLineModuleDirectoryWatcher.h | 19 +++-- .../Core/ctkCmdLineModuleFrontend.h | 85 ++++++++++++++++++- .../Core/ctkCmdLineModuleFrontendFactory.h | 3 + .../Core/ctkCmdLineModuleFuture.h | 5 ++ .../Core/ctkCmdLineModuleFutureInterface.h | 4 + .../Core/ctkCmdLineModuleManager.h | 2 + .../Core/ctkCmdLineModuleParameter.h | 6 +- .../Core/ctkCmdLineModuleParameterGroup.h | 7 +- .../Core/ctkCmdLineModulePathBuilder.h | 5 +- .../Core/ctkCmdLineModuleReference.h | 3 + .../Core/ctkCmdLineModuleResult.h | 5 ++ .../Core/ctkCmdLineModuleRunException.h | 5 ++ .../Core/ctkCmdLineModuleXmlException.h | 2 + .../Core/ctkCmdLineModuleXmlMsgHandler_p.h | 5 ++ .../Core/ctkCmdLineModuleXmlParser_p.h | 6 ++ .../Core/ctkCmdLineModuleXmlProgressWatcher.h | 5 ++ .../Core/ctkCmdLineModuleXmlValidator.h | 2 + .../Core/ctkCmdLineModuleXslTransform.h | 2 + .../Documentation/CTKCommandLineModules.dox | 20 ++++- .../ctkCmdLineModuleFrontendFactoryQtGui.h | 5 ++ .../QtGui/ctkCmdLineModuleFrontendQtGui.h | 5 ++ .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h | 1 + .../ctkCmdLineModuleObjectTreeWalker_p.h | 4 +- .../ctkCmdLineModuleFrontendFactoryQtWebKit.h | 5 ++ .../ctkCmdLineModuleFrontendQtWebKit_p.h | 5 ++ 40 files changed, 339 insertions(+), 40 deletions(-) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h index 2e513fea4f..486da304e1 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h @@ -24,6 +24,10 @@ #include +/** + * \class ctkCmdLineModuleExplorerDirectorySettings + * \brief Example application settings panel. + */ class ctkCmdLineModuleExplorerDirectorySettings : public ctkSettingsPanel { public: diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h index 1a1542a4c8..9bf5247b70 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h @@ -39,7 +39,10 @@ namespace Ui { class ctkCmdLineModuleExplorerMainWindow; } - +/** + * \class ctkCLModuleExplorerMainWindow + * \brief Example application main window. + */ class ctkCLModuleExplorerMainWindow : public QMainWindow { Q_OBJECT diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h index c22358d87e..5130d74cbd 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerProgressWidget.h @@ -34,6 +34,10 @@ namespace Ui { class ctkCmdLineModuleExplorerProgressWidget; } +/** + * \class ctkCmdLineModuleExplorerProgressWidget + * \brief Example application progress update widget. + */ class ctkCmdLineModuleExplorerProgressWidget : public QWidget { Q_OBJECT diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h index 43f670e245..0c1f8b02c3 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h @@ -31,6 +31,10 @@ class ctkCmdLineModuleManager; class QTabWidget; class QModelIndex; +/** + * \class ctkCmdLineModuleExplorerTabList + * \brief Example application tab list + */ class ctkCmdLineModuleExplorerTabList : public QObject { Q_OBJECT diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h index 7b0c9c39b1..b610f6d583 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h @@ -29,6 +29,10 @@ class ctkCmdLineModuleFrontend; struct ctkCmdLineModuleFrontendFactory; +/** + * \class ctkCmdLineModuleExplorerTreeWidget + * \brief Example application tree widget. + */ class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget { Q_OBJECT diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h index 7e111d979f..6d06a96f7c 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleBackendFunctionPointer.h @@ -91,6 +91,11 @@ Q_DECLARE_METATYPE(QList*) struct ctkCmdLineModuleBackendFunctionPointerPrivate; +/** + * \class ctkCmdLineModuleBackendFunctionPointer + * \brief Provides a back-end implementation to enable directly calling a function pointer. + * \ingroup CommandLineModulesBackendFunctionPointer + */ class CTK_CMDLINEMODULEBACKENDFP_EXPORT ctkCmdLineModuleBackendFunctionPointer : public ctkCmdLineModuleBackend { diff --git a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h index 2fb58dcf78..54f047374b 100644 --- a/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h +++ b/Libs/CommandLineModules/Backend/FunctionPointer/ctkCmdLineModuleFunctionPointerTask_p.h @@ -28,6 +28,12 @@ #include +/** + * \class ctkCmdLineModuleFunctionPointerTask + * \brief Provides a ctkCmdLineModuleFutureInterface implementation specifically to + * run a function pointer asynchronousely. + * \ingroup CommandLineModulesBackendFunctionPointer + */ class ctkCmdLineModuleFunctionPointerTask : public ctkCmdLineModuleFutureInterface, public QRunnable { public: diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h index 11c88dcaac..1d0cd12640 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleBackendLocalProcess.h @@ -30,6 +30,12 @@ struct ctkCmdLineModuleBackendLocalProcessPrivate; +/** + * \class ctkCmdLineModuleBackendLocalProcess + * \brief Provides an ctkCmdLineModuleBackend implementation + * to run a locally installed command line application. + * \ingroup CommandLineModulesBackendLocalProcess + */ class CTK_CMDLINEMODULEBACKENDLP_EXPORT ctkCmdLineModuleBackendLocalProcess : public ctkCmdLineModuleBackend { diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h index 9d2dc48c2b..f014900005 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.h @@ -37,6 +37,12 @@ class QProcess; struct ctkCmdLineModuleProcessTaskPrivate; +/** + * \class ctkCmdLineModuleProcessTask + * \brief Implements ctkCmdLineModuleFutureInterface to enabling + * running a command line application asynchronously. + * \ingroup CommandLineModulesBackendLocalProcess + */ class CTK_CMDLINEMODULEBACKENDLP_EXPORT ctkCmdLineModuleProcessTask : public ctkCmdLineModuleFutureInterface, public QRunnable { diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h index f607fe4a36..7cc88d34c2 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h @@ -33,6 +33,11 @@ class ctkCmdLineModuleResult; class QProcess; +/** + * \class ctkCmdLineModuleProcessWatcher + * \brief Provides progress updates using QFutureWatcher + * \ingroup CommandLineModulesBackendLocalProcess + */ class ctkCmdLineModuleProcessWatcher : public QObject { Q_OBJECT diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h index e00d4448db..8c0b408761 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h @@ -30,16 +30,44 @@ class ctkCmdLineModuleFuture; template class QList; class QUrl; +/** + * \class ctkCmdLineModuleBackend + * \brief Abstract base class for all back-end command line module + * implementations. + * \ingroup CommandLineModulesCore + * \see ctkCmdLineModuleBackendLocalProcess + * \see ctkCmdLineModuleBackendFunctionPointer + */ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend { ~ctkCmdLineModuleBackend(); + /** + * @brief Returns the name of the type of the backend, not the name + * of the thing or application that is run. + * @return A QString containing the name. + */ virtual QString name() const = 0; + + /** + * @brief Returns a brief description of the type of the backend. + * @return A QString containing a description. + */ virtual QString description() const = 0; + /** + * @brief Returns a list of the capabilities or the types of things + * that this back-end can run. + * @return A list of "schemes", meaning the capabilities. + */ virtual QList schemes() const = 0; + /** + * @brief Returns a timestap of the backend, which for example in the + * case of the LocalProcess may be the last modified time of the command line + * application. + */ virtual qint64 timeStamp(const QUrl& location) const = 0; /** @@ -57,10 +85,12 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend friend class ctkCmdLineModuleManager; + /** + * @brief The main method to actually execute the back-end process. + * @param A pointer to a front end implementation. + */ virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend) = 0; - //virtual ctkCmdLineModule* createModule(const QString& scheme) = 0; - }; #endif // CTKCMDLINEMODULEBACKEND_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h index 0338a3279a..b782875007 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h @@ -28,6 +28,12 @@ struct ctkCmdLineModuleCachePrivate; class QUrl; +/** + * \class ctkCmdLineModuleCache + * \brief Private non-exported class to contain a cache of + * XML descriptions and time-stamps. + * \ingroup CommandLineModulesCore + */ class ctkCmdLineModuleCache { @@ -36,13 +42,42 @@ class ctkCmdLineModuleCache ctkCmdLineModuleCache(const QString& cacheDir); ~ctkCmdLineModuleCache(); + /** + * @brief Returns the directory containing the cached information. + * @return a directory path + */ QString cacheDir() const; + /** + * @brief Returns the cached XML associated with a module. + * @param moduleLocation QUrl representing the location, + * for example a file path for a local process. + * @return QByteArray the XML + */ QByteArray rawXmlDescription(const QUrl& moduleLocation) const; + + /** + * @brief Returns the time stamp associated with a module. + * @param moduleLocation QUrl representing the location, + * for example a file path for a local process. + * @return time since epoch + */ qint64 timeStamp(const QUrl& moduleLocation) const; + /** + * @brief Adds a modules XML and timestamp to the cache. + * @param moduleLocation QUrl representing the location, + * for example a file path for a local process. + * @param timestamp the time + * @param xmlDescription the XML + */ void cacheXmlDescription(const QUrl& moduleLocation, qint64 timestamp, const QByteArray& xmlDescription); + /** + * @brief Removes an entry from the cache. + * @param moduleLocation QUrl representing the location, + * for example a file path for a local process. + */ void removeCacheEntry(const QUrl& moduleLocation); private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp index 0c539aa217..95a95427f0 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.cpp @@ -2,8 +2,7 @@ Library: CTK - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics + Copyright (c) University College London Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h index 60e0bfe2fe..26feb7ed20 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h @@ -2,8 +2,7 @@ Library: CTK - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics + Copyright (c) University College London Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,14 +29,16 @@ class ctkCmdLineModuleDefaultPathBuilderPrivate; /** * \class ctkCmdLineModuleDefaultPathBuilder - * \brief Builds up a list of directory paths to search for command line modules. + * \brief Builds up a list of directory paths to search for command + * line modules. + * \ingroup CommandLineModulesCore + * \author m.clarkson@ucl.ac.uk * - * Unfinished: + * Implements the following basic strategy, depending on which boolean + * flags are on: By default they are all off, as directory scanning is + * often time consuming. * *
- * Implements the following basic strategy, depending on which boolean flags are on:
- * By default they are all off, as directory scanning is often time consuming.
- *
  * 1. CTK_MODULE_LOAD_PATH environment variable
  * 2. Home directory
  * 3. Home directory / cli-modules
@@ -46,8 +47,6 @@ class ctkCmdLineModuleDefaultPathBuilderPrivate;
  * 6. Application directory
  * 7. Application directory / cli-modules
  * 
- * - * \author m.clarkson@ucl.ac.uk */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDefaultPathBuilder { @@ -57,14 +56,35 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDefaultPathBuilder ctkCmdLineModuleDefaultPathBuilder(); ~ctkCmdLineModuleDefaultPathBuilder(); + /** + * @brief Instruct the builder to include the users + * home directory and sub-folder cli-modules. + */ virtual void setLoadFromHomeDir(bool doLoad); + /** + * @brief Instruct the builder to include the current + * running directory and sub-folder cli-modules. + */ virtual void setLoadFromCurrentDir(bool doLoad); + /** + * @brief Instruct the builder to include the application + * installation directory and sub-folder cli-modules. + */ virtual void setLoadFromApplicationDir(bool doLoad); + /** + * @brief Instruct the builder to include the path denoted + * by the environment variable CTK_MODULE_LOAD_PATH. + */ virtual void setLoadFromCtkModuleLoadPath(bool doLoad); + /** + * @brief Builds the list of paths to search and returns them + * as QStringList + * @return a QStringList of directory path names + */ virtual QStringList build() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h index 00d9e86c9d..76359a6cb1 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h @@ -35,10 +35,10 @@ class ctkCmdLineModuleParameterGroup; class ctkCmdLineModuleParameter; /** + * \class ctkCmdLineModuleDescription + * \brief Description of the parameters of a command line module. * \ingroup CommandLineModulesCore * - * Description of the parameters of a command line module. - * * The parameters can be used for automated GUI generation or execution * of the module. */ diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h index ea00efb63a..9d8f1dd883 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h @@ -33,15 +33,18 @@ class ctkCmdLineModuleDirectoryWatcherPrivate; /** * \class ctkCmdLineModuleDirectoryWatcher - * \brief Provides directory scanning to load new modules into a ctkCmdLineModuleManager. + * \brief Provides directory scanning to automatically load new modules + * into a ctkCmdLineModuleManager. * \ingroup CommandLineModulesCore * \author m.clarkson@ucl.ac.uk * - * This class provides directory scanning and automatic loading of command line modules. - * The client should call setDirectories() to set the list of directories, and listen - * to the signal modulesChanged to know when to re-build the GUI representation. + * This class provides directory scanning and automatic loading of command + * line modules. The client should call setDirectories() to set the list of + * directories, and listen to the signal modulesChanged to know when to + * re-build the GUI representation. */ -class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QObject +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher +: public QObject { Q_OBJECT @@ -58,7 +61,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QOb /** * \brief Set the directories to be watched. - * \param directories a StringList of directory names. If any of these are invalid, they will be filtered out and ignored. + * \param directories a StringList of directory names. If any of these are + * invalid, they will be filtered out and ignored. */ void setDirectories(const QStringList& directories); @@ -68,7 +72,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDirectoryWatcher : public QOb QStringList directories() const; /** - * \brief Returns the list of files (command line apps) currently being watched. + * \brief Returns the list of files (command line apps) + * currently being watched. */ QStringList files() const; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 3551007328..03aaa703e3 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -35,7 +35,12 @@ class ctkCmdLineModuleParameter; struct ctkCmdLineModuleFrontendPrivate; /** + * \class ctkCmdLineModuleFrontend + * \brief Abstract base class for all front-end command + * line module implementations. * \ingroup CommandLineModulesCore + * \see ctkCmdLineModuleFrontendQtGui + * \see ctkCmdLineModuleFrontendQtWebKit */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject { @@ -45,7 +50,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject enum ParameterValueRole { - /* Data returned using this role must no be of any type not supported by + /* Data returned using this role must not be of any type not supported by QVariant by default. For complex parameter types (like file, image, geometry, etc.) the data must be convertible to a QString pointing to a local resource. @@ -71,37 +76,111 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject ~ctkCmdLineModuleFrontend(); + /** + * @brief Returns the GUI representation, currently supporting only + * QObject subclasses. + * @return The GUI that can then be embeded in an applicaiton + * window for instance. + */ virtual QObject* guiHandle() const = 0; - virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const = 0; + /** + * @brief GUIs will need to be able to read parameters, + * here we retrieve by role. + * @return QVariant + * @see ParameterValueRole + */ + virtual QVariant value(const QString& parameter, + int role = LocalResourceRole) const = 0; + + /** + * @brief Set the value of a certain parameters + * @param parameter The name of the parameter, as defined in the XML. + * @param value The value for that parameter. + */ virtual void setValue(const QString& parameter, const QVariant& value) = 0; + /** + * @brief Return the ctkCmdLineModuleFuture, derived from QFuture to + * provide asynchronous processing. + * @see ctkCmdLineModuleFuture + */ virtual ctkCmdLineModuleFuture future() const; + /** + * @brief Returns a QUrl to define the location of the module that is run. + * + * For a local process this may be the file location of the command + * line module. For other implementations, such as a web-service, + * this could be a web URL. + * + * @return QUrl A resource independent URL defining where the module is. + */ QUrl location() const; + /** + * @brief Returns a ctkCmdLineModuleReference value object that refers + * and provides access to the module. + * @return ctkCmdLineModuleReference + */ ctkCmdLineModuleReference moduleReference() const; + /** + * @brief Returns a list of all valid parameter names. + */ virtual QList parameterNames() const; + /** + * @brief Returns a map of parameter names and values. + */ virtual QHash values() const; + + /** + * @brief Enables the parameter values to be set. + */ virtual void setValues(const QHash& values); + /** + * @brief Indicates if the underlying process is currently active. + * @return true if running and false otherwise. + */ bool isRunning() const; + + /** + * @brief Indicates if the underlying process is currently paused. + * @return true if paused and false otherwise. + */ bool isPaused() const; Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value); // convenience methods - QList parameters(const QString& type = QString(), ParameterFilters filters = All); + /** + * @brief Useful method to return subsets of parameter objects, searhing + * by type for example "image" and filter for example "input"/"output". + * @param type The type of parameter, as defined in the XML element. + * @param filters flag to define whether we want input/output. + * @return QList of ctkCmdLineModuleParameter depending on type and filters. + * @see ParameterFilter + */ + QList parameters( + const QString& type = QString(), + ParameterFilters filters = All); void resetValues(); protected: + /** + * @brief Constructor. + */ ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef); + /** + * @brief Sets the ctkCmdLineModuleFuture which effectively + * contains the backend that is run. + */ void setFuture(const ctkCmdLineModuleFuture& future); private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h index 848cb718e6..cb36740d8a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h @@ -28,7 +28,10 @@ class ctkCmdLineModuleFrontend; class ctkCmdLineModuleReference; /** + * \class ctkCmdLineModuleFrontendFactory + * \brief Factory class to create new front-ends. * \ingroup CommandLineModulesCore + * \see ctkCmdLineModuleFrontend */ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontendFactory { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h index 93983d345c..b49852717b 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h @@ -27,6 +27,11 @@ #include /** + * \class ctkCmdLineModuleFuture + * \brief QFuture sub-class with in addition canCancel() and canPause(). + * \ingroup CommandLineModulesCore + * + * * QFuture sub-class with two additional methods: * * - bool canCancel() diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h index 9096f94c60..e3603fa42b 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h @@ -28,6 +28,10 @@ class ctkCmdLineModuleFuture; +/** + * \class ctkCmdLineModuleFutureInterface + * \ingroup CommandLineModulesCore + */ template <> class QFutureInterface : public QFutureInterfaceBase { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h index 209f9c7625..765ac4c14b 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.h @@ -36,6 +36,8 @@ class ctkCmdLineModuleFuture; struct ctkCmdLineModuleManagerPrivate; /** + * \class ctkCmdLineModuleManager + * \brief Main manager class to handle loading and unloading of modules. * \ingroup CommandLineModulesCore */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleManager : public QObject diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h index 8bbd5170ec..49eccde1a9 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h @@ -31,15 +31,15 @@ class QStringList; struct ctkCmdLineModuleParameterPrivate; /** - * \ingroup CommandLineModulesCore + * \class ctkCmdLineModuleParameter + * \brief Single parameter to a module, like a threshold of a filter. + * \ingroup CommandLineModulesCore * - * \brief Single parameter to a module, like a threshold of a filter. * * ctkCmdLineModuleParameter describes a single parameters to a * module. Information on the parameter type, name, flag, label, * description, channel, index, default, and constraints can be * stored. - * */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameter { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h index 0d0669c677..194ae42c50 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h @@ -32,10 +32,9 @@ class ctkCmdLineModuleParameter; struct ctkCmdLineModuleParameterGroupPrivate; /** - * \ingroup CommandLineModulesCore - * - * \brief Group of parameters - * + * \class ctkCmdLineModuleParameterGroup + * \brief Group of parameters + * \ingroup CommandLineModulesCore */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameterGroup { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h index 7be01f404b..5d38450106 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModulePathBuilder.h @@ -2,8 +2,7 @@ Library: CTK - Copyright (c) German Cancer Research Center, - Division of Medical and Biological Informatics + Copyright (c) University College London Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +27,7 @@ /** * \class ctkCmdLineModulePathBuilder - * \brief Prototype (unfinished) interface for objects that can build + * \brief Prototype interface for objects that can build * up a list of file paths, stored in a QStringList. * \author m.clarkson@ucl.ac.uk */ diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index 55548948ff..26b7d08710 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -32,6 +32,9 @@ class ctkCmdLineModuleDescription; struct ctkCmdLineModuleReferencePrivate; /** + * \class ctkCmdLineModuleReference + * \brief Defines a reference or handle to a module, including location, + * XML, description and access to the backend. * \ingroup CommandLineModulesCore */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h index be49256650..034105c63f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h @@ -25,6 +25,11 @@ #include #include +/** + * \class ctkCmdLineModuleResult + * \brief Describes the output of a command line module. + * \ingroup CommandLineModulesCore + */ class ctkCmdLineModuleResult { public: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h index ef766e1d7e..cc3553a1b0 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h @@ -28,6 +28,11 @@ #include +/** + * \class ctkCmdLineModuleRunException + * \brief Exception class to describe problems with running the module. + * \ingroup CommandLineModulesCore + */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkException { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h index ef4c0af252..c1ca9e8d13 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h @@ -27,6 +27,8 @@ #include "ctkCommandLineModulesCoreExport.h" /** + * \class ctkCmdLineModuleXmlException + * \brief Exception class to describe problems with XML processing. * \ingroup CommandLineModulesCore */ CTK_DECLARE_EXCEPTION(CTK_CMDLINEMODULECORE_EXPORT, ctkCmdLineModuleXmlException, ctkException) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h index cec4d26285..a9d3d5d8ad 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h @@ -24,6 +24,11 @@ #include +/** + * \class QAbstractMessageHandler + * \brief Class to handle an XML message. + * \ingroup CommandLineModulesCore + */ class ctkCmdLineModuleXmlMsgHandler : public QAbstractMessageHandler { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h index 175da1fc8f..b90939e91a 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h @@ -31,6 +31,12 @@ struct ctkCmdLineModuleParameterParser; class QIODevice; +/** + * \class ctkCmdLineModuleXmlParser + * \brief Performs XML parsing, loading data into a ctkCmdLineModuleDescription + * \ingroup CommandLineModulesCore + * \see ctkCmdLineModuleDescription + */ class ctkCmdLineModuleXmlParser { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h index e6f489fd81..547af834d7 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h @@ -30,6 +30,11 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate; class QIODevice; +/** + * \class ctkCmdLineModuleXmlProgressWatcher + * \brief Provides progress updates of a module. + * \ingroup CommandLineModulesCore + */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlProgressWatcher : public QObject { Q_OBJECT diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h index 67a629c11c..26a01382df 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h @@ -31,6 +31,8 @@ class ctkCmdLineModuleXmlValidatorPrivate; class QIODevice; /** + * \class ctkCmdLineModuleXmlValidator + * \brief Provides XML validation, comparing a modules XML to an .xsd file * \ingroup CommandLineModulesCore */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlValidator diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h index bcff75b062..55c2b1e013 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h @@ -31,6 +31,8 @@ class ctkCmdLineModuleXslTransformPrivate; class QIODevice; /** + * \class ctkCmdLineModuleXslTransform + * \brief Provides a transformation from XML to the Qt ui file format. * \ingroup CommandLineModulesCore */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform diff --git a/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox b/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox index c138e9ec89..59a97bc284 100644 --- a/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox +++ b/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox @@ -6,13 +6,29 @@ CTK provides an API for interfacing with command line modules through a self-describing XML description of the supported command line arguments. -\defgroup CommandLineModulesCore Command Line Module Support +\defgroup CommandLineModulesCore Command Line Module Core \ingroup Libs \ingroup CommandLineModules -\defgroup CommandLineModulesQtGui Command Line Module QtGui Support +\defgroup CommandLineModulesBackEnd Command Line Module Back-End \ingroup Libs \ingroup CommandLineModules +\defgroup CommandLineModulesBackendFunctionPointer Command Line Module Function Pointer +\ingroup CommandLineModulesBackEnd + +\defgroup CommandLineModulesBackendLocalProcess Command Line Module Local Process +\ingroup CommandLineModulesBackEnd + +\defgroup CommandLineModulesFrontEnd Command Line Module Front-End +\ingroup Libs +\ingroup CommandLineModules + +\defgroup CommandLineModulesFrontendQtGui Command Line Module QtGui +\ingroup CommandLineModulesFrontEnd + +\defgroup CommandLineModulesFrontendQtWebKit Command Line Module QtWebKit +\ingroup CommandLineModulesFrontEnd + */ diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h index 8fde216475..0bade246e8 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendFactoryQtGui.h @@ -27,6 +27,11 @@ #include "ctkCmdLineModuleFrontendFactory.h" #include "ctkCmdLineModuleFrontendQtGui.h" +/** + * \class ctkCmdLineModuleFrontendFactoryQtGui + * \brief Factory class to instantiate Qt widget based front-ends. + * \ingroup CommandLineModulesFrontendQtGui + */ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendFactoryQtGui : public ctkCmdLineModuleFrontendFactory { diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index dff60d8710..a9018d7f0d 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -34,6 +34,11 @@ class QWidget; struct ctkCmdLineModuleFrontendQtGuiPrivate; +/** + * \class ctkCmdLineModuleFrontendQtGui + * \brief A Qt based implementation of the module front end. + * \ingroup CommandLineModulesFrontendQtGui + */ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCmdLineModuleFrontend { diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h index b73e267773..16e362f319 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h @@ -30,6 +30,7 @@ * \class ctkCmdLineModuleMenuFactoryQtGui * \brief Takes a QHash of filename and ctkCmdLineModuleReference and produces a QMenu. * \author m.clarkson@ucl.ac.uk + * \ingroup CommandLineModulesFrontendQtGui */ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui { diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h index 965d88e610..7a7597c72f 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h @@ -30,8 +30,8 @@ class QVariant; /** * \class ctkCmdLineModuleObjectTreeWalker - * - * Note: Deliberately not exported. + * \brief Non-exported helper class to iterate through GUI widgets. + * \ingroup CommandLineModulesFrontendQtGui */ class ctkCmdLineModuleObjectTreeWalker { diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h index 3957941140..8521694050 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendFactoryQtWebKit.h @@ -26,6 +26,11 @@ #include "ctkCmdLineModuleFrontendFactory.h" +/** + * \class ctkCmdLineModuleFrontendFactoryQtWebKit + * \brief QtWebKit specific implementation of ctkCmdLineModuleFrontendFactory + * \ingroup CommandLineModulesFrontendQtWebKit + */ class CTK_CMDLINEMODULEQTWEBKIT_EXPORT ctkCmdLineModuleFrontendFactoryQtWebKit : public ctkCmdLineModuleFrontendFactory { diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h index 551ed8991b..0519b1aa57 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h @@ -26,6 +26,11 @@ class QWebView; +/** + * \class ctkCmdLineModuleFrontendQtWebKit + * \brief QtWebKit specific implementation of ctkCmdLineModuleFrontend + * \ingroup CommandLineModulesFrontendQtWebKit + */ class ctkCmdLineModuleFrontendQtWebKit : public ctkCmdLineModuleFrontend { From a231e0f037831e0e0cca62571f14dc4b63bdee0d Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Fri, 24 Aug 2012 11:38:47 +0100 Subject: [PATCH 134/247] Fix ctkCmdLineModuleFrontend::parameters search by checking for zero output on compare function --- Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp index baa39cde28..28b5d32cb5 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.cpp @@ -139,16 +139,16 @@ QList ctkCmdLineModuleFrontend::parameters(const QStr foreach(ctkCmdLineModuleParameter param, group.parameters()) { if (filters.testFlag(Input) && - (param.channel().isEmpty() || param.channel().compare("input", Qt::CaseInsensitive))) + (param.channel().isEmpty() || param.channel().compare("input", Qt::CaseInsensitive) == 0)) { - if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive)) + if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive) == 0) { parameters << param; } } - if (filters.testFlag(Output) && param.channel().compare("output", Qt::CaseInsensitive)) + if (filters.testFlag(Output) && param.channel().compare("output", Qt::CaseInsensitive) == 0) { - if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive)) + if (type.isEmpty() || param.tag().compare(type, Qt::CaseInsensitive) == 0) { parameters << param; } From 74de8df3d32087d168177c47d5d7c6f95e574917 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Fri, 24 Aug 2012 21:00:47 +0100 Subject: [PATCH 135/247] Added doxygen for ctkCmdLineModuleDescription --- .../Core/ctkCmdLineModuleDescription.h | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h index 76359a6cb1..7cab590b41 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h @@ -40,7 +40,8 @@ class ctkCmdLineModuleParameter; * \ingroup CommandLineModulesCore * * The parameters can be used for automated GUI generation or execution - * of the module. + * of the module, and are directly related to the XML schema used to define + * a command line module. */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDescription { @@ -54,31 +55,75 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDescription static ctkCmdLineModuleDescription parse(QIODevice* input); + /** + * @brief Returns the category, derived from the \code \endcode tag. + */ QString category() const; + /** + * @brief Returns the title, derived from the \code \endcode tag. + */ QString title() const; + /** + * @brief Returns the title, derived from the \code <description> \endcode tag. + */ QString description() const; + /** + * @brief Returns the title, derived from the \code <version> \endcode tag. + */ QString version() const; + /** + * @brief Returns the title, derived from the \code <documentation-url> \endcode tag. + */ QString documentationURL() const; + /** + * @brief Returns the title, derived from the \code <license> \endcode tag. + */ QString license() const; + /** + * @brief Returns the title, derived from the \code <acknowledgements> \endcode tag. + */ QString acknowledgements() const; + /** + * @brief Returns the title, derived from the \code <contributor> \endcode tag. + */ QString contributor() const; + /** + * @brief Should return a QIcon, but does not appear to be supported yet. + */ QIcon logo() const; + /** + * \brief The XML can define groups of parameters, so this method returns + * a QList of ctkCmdLineModuleParameterGroup to handle groups. + */ QList<ctkCmdLineModuleParameterGroup> parameterGroups() const; + /** + * @brief Searches the list of parameters, checking if a parameter has the given name. + * @param name the name of the parameter, derived from the \code <name> \endcode tag. + * @return true if this module has a parameter called name and false otherwise + */ bool hasParameter(const QString& name) const; + /** + * @brief Returns the parameter specified by name + * @param name the name of the parameter, derived from the \code <name> \endcode tag. + * @return the parameter + * @throw ctkInvalidArgumentException if this module does not have this parameter. + */ ctkCmdLineModuleParameter parameter(const QString& name) const; - // Does the module have any simple (primitive) return types? + /** + * @brief Does the module have any simple (primitive) return types? + */ bool hasReturnParameters() const; private: From 0de5ad082c0ba0d68056ca40a4e31ea2b9bd0556 Mon Sep 17 00:00:00 2001 From: Julien Finet <julien.finet@kitware.com> Date: Mon, 27 Aug 2012 01:25:58 -0400 Subject: [PATCH 136/247] Add more controls to ctkPathLineEdit Add browse button Control visibility of history button (use QComboBox or QLineEdit) Improved auto sizeHint Better support for history QSettings Issue #14 --- Libs/Widgets/ctkPathLineEdit.cpp | 253 ++++++++++++++++++++++++++++--- Libs/Widgets/ctkPathLineEdit.h | 80 ++++++++-- 2 files changed, 294 insertions(+), 39 deletions(-) diff --git a/Libs/Widgets/ctkPathLineEdit.cpp b/Libs/Widgets/ctkPathLineEdit.cpp index 136c88c94a..03a6bdbe4d 100644 --- a/Libs/Widgets/ctkPathLineEdit.cpp +++ b/Libs/Widgets/ctkPathLineEdit.cpp @@ -29,6 +29,8 @@ #include <QRegExp> #include <QRegExpValidator> #include <QSettings> +#include <QStyleOptionComboBox> +#include <QToolButton> // CTK includes #include "ctkPathLineEdit.h" @@ -45,9 +47,17 @@ class ctkPathLineEditPrivate public: ctkPathLineEditPrivate(ctkPathLineEdit& object); void init(); + QSize sizeHint(const QString& text)const; void updateFilter(); + void createPathLineEditWidget(bool useComboBox); + QString settingKey()const; + + QLineEdit* LineEdit; QComboBox* ComboBox; + QToolButton* BrowseButton; //!< "..." button + + int MinimumContentsLength; QString Label; //!< used in file dialogs QStringList NameFilters; //!< Regular expression (in wildcard mode) used to help the user to complete the line @@ -59,6 +69,7 @@ class ctkPathLineEditPrivate #endif bool HasValidInput; //!< boolean that stores the old state of valid input + QString SettingKey; static QString sCurrentDirectory; //!< Content the last value of the current directory static int sMaxHistory; //!< Size of the history, if the history is full and a new value is added, the oldest value is dropped @@ -71,7 +82,10 @@ int ctkPathLineEditPrivate::sMaxHistory = 5; ctkPathLineEditPrivate::ctkPathLineEditPrivate(ctkPathLineEdit& object) :q_ptr(&object) { + this->LineEdit = 0; this->ComboBox = 0; + this->BrowseButton = 0; + this->MinimumContentsLength = 17; this->HasValidInput = false; this->Filters = QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Readable; } @@ -80,20 +94,106 @@ ctkPathLineEditPrivate::ctkPathLineEditPrivate(ctkPathLineEdit& object) void ctkPathLineEditPrivate::init() { Q_Q(ctkPathLineEdit); - this->ComboBox = new QComboBox(q); + QHBoxLayout* layout = new QHBoxLayout(q); - layout->addWidget(this->ComboBox); layout->setContentsMargins(0,0,0,0); + layout->setSpacing(0); // no space between the combobx and button + + this->createPathLineEditWidget(true); + + this->BrowseButton = new QToolButton(q); + this->BrowseButton->setText("..."); + // Don't vertically stretch the path line edit unnecessary + this->BrowseButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored)); + this->BrowseButton->setToolTip(q->tr("Open a dialog")); + + QObject::connect(this->BrowseButton,SIGNAL(clicked()), + q, SLOT(browse())); + + layout->addWidget(this->BrowseButton); - this->ComboBox->setEditable(true); q->setSizePolicy(QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed, QSizePolicy::LineEdit)); +} + +//------------------------------------------------------------------------------ +void ctkPathLineEditPrivate::createPathLineEditWidget(bool useComboBox) +{ + Q_Q(ctkPathLineEdit); + + QString path = q->currentPath(); - QObject::connect(this->ComboBox,SIGNAL(editTextChanged(QString)), + if (useComboBox) + { + this->ComboBox = new QComboBox(q); + this->ComboBox->setEditable(true); + this->ComboBox->setInsertPolicy(QComboBox::NoInsert); + this->LineEdit = this->ComboBox->lineEdit(); + } + else + { + this->ComboBox = 0; + this->LineEdit = new QLineEdit(q); + } + + if (q->layout() && q->layout()->itemAt(0)) + { + delete q->layout()->itemAt(0)->widget(); + } + qobject_cast<QHBoxLayout*>(q->layout())->insertWidget( + 0, + this->ComboBox ? qobject_cast<QWidget*>(this->ComboBox) : + qobject_cast<QWidget*>(this->LineEdit)); + + this->updateFilter(); + q->retrieveHistory(); + q->setCurrentPath(path); + + QObject::connect(this->LineEdit, SIGNAL(textChanged(QString)), q, SLOT(setCurrentDirectory(QString))); - QObject::connect(this->ComboBox,SIGNAL(editTextChanged(QString)), + QObject::connect(this->LineEdit, SIGNAL(textChanged(QString)), q, SLOT(updateHasValidInput())); + q->updateGeometry(); +} + +//------------------------------------------------------------------------------ +QSize ctkPathLineEditPrivate::sizeHint(const QString& text)const +{ + Q_Q(const ctkPathLineEdit); + int frame = 0; + if (this->ComboBox) + { + QStyleOptionComboBox option; + int arrowWidth = this->ComboBox->style()->subControlRect( + QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, this->ComboBox).width() + + (this->ComboBox->hasFrame() ? 2 : 0); + frame = 2 * (this->ComboBox->hasFrame() ? 3 : 0) + + arrowWidth + + 1; // for mac style, not sure why + } + else + { + QStyleOptionFrame option; + int frameWidth = this->LineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q); + int horizontalMargin = 2; // QLineEditPrivate::horizontalMargin + // See QLineEdit::sizeHint + frame = 2 * frameWidth + + this->LineEdit->textMargins().left() + + this->LineEdit->textMargins().right() + + this->LineEdit->contentsMargins().left() + + this->LineEdit->contentsMargins().right() + + 2 * horizontalMargin; + } + int browseWidth = 0; + if (q->showBrowseButton()) + { + browseWidth = this->BrowseButton->minimumSizeHint().width(); + } + int textWidth = this->LineEdit->fontMetrics().width(text); + int height = (this->ComboBox ? this->ComboBox->minimumSizeHint() : + this->LineEdit->minimumSizeHint()).height(); + return QSize(frame + textWidth + browseWidth, height); } //----------------------------------------------------------------------------- @@ -106,7 +206,20 @@ void ctkPathLineEditPrivate::updateFilter() ctk::nameFiltersToExtensions(this->NameFilters), this->Filters | QDir::NoDotAndDotDot | QDir::AllDirs, QDir::Name|QDir::DirsLast, newCompleter)); - this->ComboBox->setCompleter(newCompleter); + this->LineEdit->setCompleter(newCompleter); + + // don't accept invalid path + QRegExpValidator* validator = new QRegExpValidator( + ctk::nameFiltersToRegExp(this->NameFilters), q); + this->LineEdit->setValidator(validator); +} + +//----------------------------------------------------------------------------- +QString ctkPathLineEditPrivate::settingKey()const +{ + Q_Q(const ctkPathLineEdit); + return QString("ctkPathLineEdit/") + + (this->SettingKey.isEmpty() ? q->objectName() : this->SettingKey); } //----------------------------------------------------------------------------- @@ -162,9 +275,6 @@ void ctkPathLineEdit::setNameFilters(const QStringList &nameFilters) Q_D(ctkPathLineEdit); d->NameFilters = nameFilters; d->updateFilter(); - d->ComboBox->lineEdit()->setValidator( - new QRegExpValidator( - ctk::nameFiltersToRegExp(d->NameFilters), this)); } //----------------------------------------------------------------------------- @@ -273,12 +383,18 @@ void ctkPathLineEdit::browse() void ctkPathLineEdit::retrieveHistory() { Q_D(ctkPathLineEdit); + if (d->ComboBox == 0) + { + return; + } + QString path = this->currentPath(); + bool wasBlocking = this->blockSignals(true); d->ComboBox->clear(); // fill the combobox using the QSettings QSettings settings; - QString key = "ctkPathLineEdit/" + this->objectName(); - QStringList history = settings.value(key).toStringList(); - foreach(QString path, history) + QString key = d->settingKey(); + const QStringList history = settings.value(key).toStringList(); + foreach(const QString& path, history) { d->ComboBox->addItem(path); if (d->ComboBox->count() >= ctkPathLineEditPrivate::sMaxHistory) @@ -286,25 +402,32 @@ void ctkPathLineEdit::retrieveHistory() break; } } - //select the most recent file location - if (this->currentPath().isEmpty()) + // Restore path or select the most recent file location if none set. + if (path.isEmpty()) { + this->blockSignals(wasBlocking); d->ComboBox->setCurrentIndex(0); } + else + { + this->setCurrentPath(path); + this->blockSignals(wasBlocking); + } } //----------------------------------------------------------------------------- void ctkPathLineEdit::addCurrentPathToHistory() { Q_D(ctkPathLineEdit); - if (this->currentPath().isEmpty()) + if (d->ComboBox == 0 || + this->currentPath().isEmpty()) { return; } QSettings settings; //keep the same values, add the current value //if more than m_MaxHistory entrees, drop the oldest. - QString key = "ctkPathLineEdit/" + this->objectName(); + QString key = d->settingKey(); QStringList history = settings.value(key).toStringList(); if (history.contains(this->currentPath())) { @@ -312,7 +435,7 @@ void ctkPathLineEdit::addCurrentPathToHistory() } history.push_front(this->currentPath()); settings.setValue(key, history); - int index =d->ComboBox->findText(this->currentPath()); + int index = d->ComboBox->findText(this->currentPath()); if (index >= 0) { d->ComboBox->removeItem(index); @@ -352,14 +475,14 @@ QComboBox* ctkPathLineEdit::comboBox() const QString ctkPathLineEdit::currentPath()const { Q_D(const ctkPathLineEdit); - return d->ComboBox->currentText(); + return d->LineEdit ? d->LineEdit->text() : QString(); } //------------------------------------------------------------------------------ void ctkPathLineEdit::setCurrentPath(const QString& path) { Q_D(ctkPathLineEdit); - d->ComboBox->setEditText(path); + d->LineEdit->setText(path); } //------------------------------------------------------------------------------ @@ -374,16 +497,100 @@ void ctkPathLineEdit::updateHasValidInput() Q_D(ctkPathLineEdit); bool oldHasValidInput = d->HasValidInput; - d->HasValidInput = d->ComboBox->lineEdit()->hasAcceptableInput(); + d->HasValidInput = d->LineEdit->hasAcceptableInput(); if (d->HasValidInput) { - QFileInfo fileInfo(d->ComboBox->currentText()); + QFileInfo fileInfo(this->currentPath()); ctkPathLineEditPrivate::sCurrentDirectory = fileInfo.isFile() ? fileInfo.absolutePath() : fileInfo.absoluteFilePath(); - emit currentPathChanged(d->ComboBox->currentText()); + emit currentPathChanged(this->currentPath()); } - if ( d->HasValidInput != oldHasValidInput) + if (d->HasValidInput != oldHasValidInput) { emit validInputChanged(d->HasValidInput); } + this->updateGeometry(); +} + +//------------------------------------------------------------------------------ +QString ctkPathLineEdit::settingKey()const +{ + Q_D(const ctkPathLineEdit); + return d->SettingKey; +} + +//------------------------------------------------------------------------------ +void ctkPathLineEdit::setSettingKey(const QString& key) +{ + Q_D(ctkPathLineEdit); + d->SettingKey = key; + this->retrieveHistory(); +} + +//------------------------------------------------------------------------------ +bool ctkPathLineEdit::showBrowseButton()const +{ + Q_D(const ctkPathLineEdit); + return d->BrowseButton->isVisibleTo(const_cast<ctkPathLineEdit*>(this)); +} + +//------------------------------------------------------------------------------ +void ctkPathLineEdit::setShowBrowseButton(bool visible) +{ + Q_D(ctkPathLineEdit); + d->BrowseButton->setVisible(visible); +} + +//------------------------------------------------------------------------------ +bool ctkPathLineEdit::showHistoryButton()const +{ + Q_D(const ctkPathLineEdit); + return d->ComboBox ? true: false; +} + +//------------------------------------------------------------------------------ +void ctkPathLineEdit::setShowHistoryButton(bool visible) +{ + Q_D(ctkPathLineEdit); + d->createPathLineEditWidget(visible); +} + +//------------------------------------------------------------------------------ +int ctkPathLineEdit::minimumContentsLength()const +{ + Q_D(const ctkPathLineEdit); + return d->MinimumContentsLength; +} + +//------------------------------------------------------------------------------ +void ctkPathLineEdit::setMinimumContentsLength(int length) +{ + Q_D(ctkPathLineEdit); + d->MinimumContentsLength = length; + this->updateGeometry(); +} + +//------------------------------------------------------------------------------ +QSize ctkPathLineEdit::minimumSizeHint()const +{ + Q_D(const ctkPathLineEdit); + QString fileName = QString('/') + QFileInfo(this->currentPath()).fileName(); + if (fileName.size() < d->MinimumContentsLength) + { + fileName = QString("x").repeated(d->MinimumContentsLength); + } + QSize hint = d->sizeHint(fileName); + return hint; +} + +//------------------------------------------------------------------------------ +QSize ctkPathLineEdit::sizeHint()const +{ + Q_D(const ctkPathLineEdit); + QString path = this->currentPath(); + if (path.size() < d->MinimumContentsLength) + { + path = QString("x").repeated(d->MinimumContentsLength); + } + return d->sizeHint(path); } diff --git a/Libs/Widgets/ctkPathLineEdit.h b/Libs/Widgets/ctkPathLineEdit.h index 14d98b09c3..e5f0823c80 100644 --- a/Libs/Widgets/ctkPathLineEdit.h +++ b/Libs/Widgets/ctkPathLineEdit.h @@ -46,15 +46,15 @@ MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #define __ctkPathLineEdit_h // Qt includes -#include <QWidget> #include <QDir> +#include <QWidget> class QComboBox; // CTK includes #include "ctkWidgetsExport.h" class ctkPathLineEditPrivate; -/** +/** * \ingroup Widgets * \brief Advanced line edit to select file or directory */ @@ -77,6 +77,33 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget Q_FLAGS(Option Options); #endif + /// This property controls the key used to search the settings for recorded + /// paths. + /// If multiple path line edits share the same key, their history is then + /// shared. + /// If an empty key string is given, the object name is used as key. + /// Setting the key automatically retrieve the history from settings + /// Empty by default. + /// \sa retrieveHistory(), addCurrentPathToHistory(), showHistoryButton + Q_PROPERTY(QString settingKey READ settingKey WRITE setSettingKey ) + + /// This property controls whether the browse ("...") button is visible or + /// not. Clicking on the button calls opens a dialog to select the current path. + /// True by default + /// \sa browse() + Q_PROPERTY(bool showBrowseButton READ showBrowseButton WRITE setShowBrowseButton); + + /// This property controls whether the history button (arrow button that opens + /// the history menu) is visible or not. + /// True by default. + /// \sa retrieveHistory(), addCurrentPathToHistory(), settingKey + Q_PROPERTY(bool showHistoryButton READ showHistoryButton WRITE setShowHistoryButton); + + /// This property holds the minimum number of characters that should fit into + /// the path line edit. + /// The default value is 17. + Q_PROPERTY(int minimumContentsLength READ minimumContentsLength WRITE setMinimumContentsLength) + public: enum Filter { Dirs = 0x001, Files = 0x002, @@ -152,14 +179,33 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget const Options& options()const; #endif - /** Change the current extension of the edit line. - * If there is no extension yet, set it - */ + /// Change the current extension of the edit line. + /// If there is no extension yet, set it void setCurrentFileExtension(const QString& extension); + QString settingKey()const; + void setSettingKey(const QString& key); + + bool showBrowseButton()const; + void setShowBrowseButton(bool visible); + + bool showHistoryButton()const; + void setShowHistoryButton(bool visible); + + int minimumContentsLength()const; + void setMinimumContentsLength(int lenght); + /// Return the combo box internally used by the path line edit QComboBox* comboBox() const; + /// The width returned, in pixels, is the length of the file name (with no + /// path) if any. Otherwise, it's enough for 15 to 20 characters. + virtual QSize minimumSizeHint()const; + + /// The width returned, in pixels, is the entire length of the current path + /// if any. Otherwise, it's enough for 15 to 20 characters. + virtual QSize sizeHint()const; + Q_SIGNALS: /** the signal is emit when the state of hasValidInput changed */ @@ -170,20 +216,22 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget public Q_SLOTS: void setCurrentPath(const QString& path); - /** Open a QFileDialog to select a file or directory and set current text to it - * You would probably connect a browse push button like this: - * connect(myPushButton,SIGNAL(clicked()),myPathLineEdit,SLOT(browse())) - */ + /// Open a QFileDialog to select a file or directory and set current text to it + /// You would probably connect a browse push button like this: + /// connect(myPushButton,SIGNAL(clicked()),myPathLineEdit,SLOT(browse())) + /// As a conveniency, such button is provided by default via the browseButton + /// \sa showBrowseButton void browse(); - /** Load the history of the paths. To be restored the inputs must have been saved by - * saveCurrentPathInHistory(). - */ - + /// Load the history of the paths that have been saved in the application + /// settings with addCurrentPathToHistory(). + /// The history is identified using \a settingKey + /// \sa addCurrentPathToHistory(), showHistoryButton, settingKey void retrieveHistory(); - /** Save the current value (this->currentPath()) into the history. That value will be retrieved - * next time the retrieveHistory() - */ + + /// Save the current value (this->currentPath()) into the history. That value + /// will be retrieved next time retrieveHistory() is called. + /// \sa retrieveHistory(), showHistoryButton, settingKey void addCurrentPathToHistory(); protected Q_SLOTS: From 46438451e5f1a4c69f7f9aaf5174587fa96bda87 Mon Sep 17 00:00:00 2001 From: Steve Pieper <pieper@isomics.com> Date: Mon, 27 Aug 2012 10:32:11 -0400 Subject: [PATCH 137/247] BUG: Slicer 1977 - retrieve enabled based on query Previously retrieve was enabled when rows of the query tree where selected. But this was not taken into account and all studies were retrieved, not just the selected ones. Now the button is enabled if there are any studies and the query results tree is not selectable. http://na-mic.org/Bug/view.php?id=1977 --- .../Widgets/ctkDICOMQueryRetrieveWidget.cpp | 109 +++++++++--------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp index 93afd6677f..f7d98c8cc7 100644 --- a/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp +++ b/Libs/DICOM/Widgets/ctkDICOMQueryRetrieveWidget.cpp @@ -107,7 +107,7 @@ void ctkDICOMQueryRetrieveWidgetPrivate::init() QObject::connect(this->CancelButton, SIGNAL(clicked()), q, SLOT(cancel())); this->results->setModel(&this->Model); - this->results->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->results->setSelectionMode(QAbstractItemView::NoSelection); this->results->setSelectionBehavior(QAbstractItemView::SelectRows); QObject::connect(this->results->selectionModel(), @@ -240,6 +240,7 @@ void ctkDICOMQueryRetrieveWidget::query() { d->Model.setDatabase(d->QueryResultDatabase.database()); } + d->RetrieveButton->setEnabled(d->QueriesByStudyUID.keys().size() != 0); progress.setValue(progress.maximum()); d->ProgressDialog = 0; @@ -256,21 +257,23 @@ void ctkDICOMQueryRetrieveWidget::retrieve() return; } - // for each of the selected server nodes, send the query QProgressDialog progress("Retrieve from DICOM servers", "Cancel", 0, 0, this, Qt::WindowTitleHint | Qt::WindowSystemMenuHint); // We don't want the progress dialog to resize itself, so we bypass the label // by creating our own QLabel* progressLabel = new QLabel(tr("Initialization...")); - if(d->UseProgressDialog){ - progress.setLabel(progressLabel); - d->ProgressDialog = &progress; - progress.setWindowModality(Qt::ApplicationModal); - progress.setMinimumDuration(0); - progress.setValue(0); - progress.setMaximum(0); - progress.setAutoClose(false); - progress.show(); + + // for each of the selected server nodes, send the query + if(d->UseProgressDialog) + { + progress.setLabel(progressLabel); + d->ProgressDialog = &progress; + progress.setWindowModality(Qt::ApplicationModal); + progress.setMinimumDuration(0); + progress.setValue(0); + progress.setMaximum(0); + progress.setAutoClose(false); + progress.show(); } QMap<QString,QVariant> serverParameters = d->ServerNodeWidget->parameters(); @@ -281,17 +284,18 @@ void ctkDICOMQueryRetrieveWidget::retrieve() retrieve->setMoveDestinationAETitle( serverParameters["StorageAETitle"].toString() ); // do the rerieval for each selected series + // that is selected in the tree view foreach( QString studyUID, d->QueriesByStudyUID.keys() ) { - if(d->UseProgressDialog){ - if (progress.wasCanceled()) + if(d->UseProgressDialog) { - break; - } - - progressLabel->setText(QString(tr("Retrieving:\n%1")).arg(studyUID)); - this->updateRetrieveProgress(0); + if (progress.wasCanceled()) + { + break; } + progressLabel->setText(QString(tr("Retrieving:\n%1")).arg(studyUID)); + this->updateRetrieveProgress(0); + } // Get information which server we want to get the study from and prepare request accordingly ctkDICOMQuery *query = d->QueriesByStudyUID[studyUID]; @@ -305,13 +309,14 @@ void ctkDICOMQueryRetrieveWidget::retrieve() logger.debug("About to retrieve " + studyUID + " from " + d->QueriesByStudyUID[studyUID]->host()); logger.info ( "Starting to retrieve" ); - if(d->UseProgressDialog){ - connect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel())); - connect(retrieve, SIGNAL(progress(QString)), - progressLabel, SLOT(setText(QString))); - connect(retrieve, SIGNAL(progress(int)), - this, SLOT(updateRetrieveProgress(int))); - } + if(d->UseProgressDialog) + { + connect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel())); + connect(retrieve, SIGNAL(progress(QString)), + progressLabel, SLOT(setText(QString))); + connect(retrieve, SIGNAL(progress(int)), + this, SLOT(updateRetrieveProgress(int))); + } try { // perform the retrieve @@ -327,45 +332,41 @@ void ctkDICOMQueryRetrieveWidget::retrieve() catch (std::exception e) { logger.error ( "Retrieve failed" ); - if(d->UseProgressDialog){ - if ( QMessageBox::question ( this, - tr("Query Retrieve"), tr("Retrieve failed. Keep trying?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + if(d->UseProgressDialog) { - continue; - } - else - { - break; + if ( QMessageBox::question ( this, + tr("Query Retrieve"), tr("Retrieve failed. Keep trying?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + { + continue; + } + else + { + break; + } } } - } - if(d->UseProgressDialog){ - disconnect(retrieve, SIGNAL(progress(QString)), - progressLabel, SLOT(setText(QString))); - disconnect(retrieve, SIGNAL(progress(int)), - this, SLOT(updateRetrieveProgress(int))); - disconnect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel())); - } - // Store retrieve structure for later use. - // Comment MO: I do not think that makes much sense; you store per study one fat - // structure including an SCU. Also, I switched the code to re-use the retrieve - // SCU in order to not start/stop the association for every study. In general, - // it would make most sense in my opinion to have one SCU for each server you - // like to retrieve from. There is no good reason to have one for each study. - // d->RetrievalsByStudyUID[studyUID] = retrieve; + if(d->UseProgressDialog) + { + disconnect(retrieve, SIGNAL(progress(QString)), + progressLabel, SLOT(setText(QString))); + disconnect(retrieve, SIGNAL(progress(int)), + this, SLOT(updateRetrieveProgress(int))); + disconnect(&progress, SIGNAL(canceled()), retrieve, SLOT(cancel())); + } logger.info ( "Retrieve success" ); } + if(d->UseProgressDialog) - { + { QString message(tr("Retrieve Process Finished")); if (retrieve->wasCanceled()) { message = tr("Retrieve Process Canceled"); } QMessageBox::information ( this, tr("Query Retrieve"), message ); - } + } emit studiesRetrieved(d->RetrievalsByStudyUID.keys()); delete retrieve; @@ -440,7 +441,11 @@ void ctkDICOMQueryRetrieveWidget::onSelectionChanged(const QItemSelection &selec Q_D(ctkDICOMQueryRetrieveWidget); logger.debug("Selection change"); - d->RetrieveButton->setEnabled(d->results->selectionModel()->hasSelection()); + // TODO: allow selection of individual studies to retrieve. Requires + // monitoring the selection and mapping to the study list (which is not + // straightforward because the dataroles of patient and series don't + // map directly to studies). + //d->RetrieveButton->setEnabled(d->results->selectionModel()->hasSelection()); } QMap<QString,QVariant> ctkDICOMQueryRetrieveWidget::getServerParameters() From 3f28910a32e827c66b165dab8f7f4ca4f28ea879 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:54:51 +0200 Subject: [PATCH 138/247] Reworked ctkDirectoryListWidget for improved flexibility. There is now a ctkPathListWidget which is a specialized QListView and a separate ctkPathListButtonsWidget which is meant to work together with a ctkPathListWidget instance. Both widgets can be layed out and customized in the Qt designer independently. --- Libs/Widgets/CMakeLists.txt | 21 +- Libs/Widgets/Plugins/CMakeLists.txt | 6 + .../ctkPathListButtonsWidgetPlugin.cpp | 70 ++ .../Plugins/ctkPathListButtonsWidgetPlugin.h | 46 + .../Plugins/ctkPathListWidgetPlugin.cpp | 70 ++ .../Widgets/Plugins/ctkPathListWidgetPlugin.h | 46 + Libs/Widgets/Plugins/ctkWidgetsPlugins.h | 4 + .../Resources/UI/ctkDirectoryListWidget.ui | 97 --- .../Resources/UI/ctkPathListButtonsWidget.ui | 64 ++ Libs/Widgets/Testing/Cpp/CMakeLists.txt | 6 + .../Testing/Cpp/ctkPathListWidgetTest.cpp | 307 +++++++ .../Cpp/ctkPathListWidgetWithButtonsTest.cpp | 99 +++ Libs/Widgets/ctkDirectoryListView.cpp | 245 ------ Libs/Widgets/ctkDirectoryListView.h | 96 --- Libs/Widgets/ctkDirectoryListWidget.cpp | 146 ---- Libs/Widgets/ctkDirectoryListWidget.h | 69 -- Libs/Widgets/ctkPathListButtonsWidget.cpp | 713 +++++++++++++++ Libs/Widgets/ctkPathListButtonsWidget.h | 157 ++++ ...idget_p.h => ctkPathListButtonsWidget_p.h} | 52 +- Libs/Widgets/ctkPathListWidget.cpp | 813 ++++++++++++++++++ Libs/Widgets/ctkPathListWidget.h | 307 +++++++ 21 files changed, 2753 insertions(+), 681 deletions(-) create mode 100644 Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.cpp create mode 100644 Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.h create mode 100644 Libs/Widgets/Plugins/ctkPathListWidgetPlugin.cpp create mode 100644 Libs/Widgets/Plugins/ctkPathListWidgetPlugin.h delete mode 100644 Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui create mode 100644 Libs/Widgets/Resources/UI/ctkPathListButtonsWidget.ui create mode 100644 Libs/Widgets/Testing/Cpp/ctkPathListWidgetTest.cpp create mode 100644 Libs/Widgets/Testing/Cpp/ctkPathListWidgetWithButtonsTest.cpp delete mode 100644 Libs/Widgets/ctkDirectoryListView.cpp delete mode 100644 Libs/Widgets/ctkDirectoryListView.h delete mode 100644 Libs/Widgets/ctkDirectoryListWidget.cpp delete mode 100644 Libs/Widgets/ctkDirectoryListWidget.h create mode 100644 Libs/Widgets/ctkPathListButtonsWidget.cpp create mode 100644 Libs/Widgets/ctkPathListButtonsWidget.h rename Libs/Widgets/{ctkDirectoryListWidget_p.h => ctkPathListButtonsWidget_p.h} (51%) create mode 100644 Libs/Widgets/ctkPathListWidget.cpp create mode 100644 Libs/Widgets/ctkPathListWidget.h diff --git a/Libs/Widgets/CMakeLists.txt b/Libs/Widgets/CMakeLists.txt index 2ee3ffcca0..2b92262a05 100644 --- a/Libs/Widgets/CMakeLists.txt +++ b/Libs/Widgets/CMakeLists.txt @@ -63,11 +63,6 @@ set(KIT_SRCS ctkDateRangeWidget.h ctkDirectoryButton.cpp ctkDirectoryButton.h - ctkDirectoryListView.cpp - ctkDirectoryListView.h - ctkDirectoryListWidget.cpp - ctkDirectoryListWidget.h - ctkDirectoryListWidget_p.h ctkDoubleRangeSlider.cpp ctkDoubleRangeSlider.h ctkDoubleSlider.cpp @@ -113,6 +108,11 @@ set(KIT_SRCS ctkModalityWidget.h ctkPathLineEdit.cpp ctkPathLineEdit.h + ctkPathListButtonsWidget.cpp + ctkPathListButtonsWidget.h + ctkPathListButtonsWidget_p.h + ctkPathListWidget.cpp + ctkPathListWidget.h ctkPixmapIconEngine.cpp ctkPixmapIconEngine.h ctkPopupWidget.cpp @@ -208,9 +208,6 @@ set(KIT_MOC_SRCS ctkCrosshairLabel.h ctkDateRangeWidget.h ctkDirectoryButton.h - ctkDirectoryListView.h - ctkDirectoryListWidget.h - ctkDirectoryListWidget_p.h ctkDoubleRangeSlider.h ctkDoubleSlider.h ctkDynamicSpacer.h @@ -234,6 +231,8 @@ set(KIT_MOC_SRCS ctkMessageBox.h ctkModalityWidget.h ctkPathLineEdit.h + ctkPathListButtonsWidget.h + ctkPathListButtonsWidget_p.h ctkPopupWidget.h ctkPopupWidget_p.h ctkQImageView.h @@ -269,6 +268,10 @@ set(KIT_MOC_SRCS ctkWorkflowWidgetStep_p.h ) +QT4_GENERATE_MOCS( + ctkPathListWidget.h +) + # UI files set(KIT_UI_FORMS Resources/UI/ctkAddRemoveComboBox.ui @@ -277,13 +280,13 @@ set(KIT_UI_FORMS Resources/UI/ctkErrorLogWidget.ui Resources/UI/ctkMaterialPropertyWidget.ui Resources/UI/ctkModalityWidget.ui + Resources/UI/ctkPathListButtonsWidget.ui Resources/UI/ctkScreenshotDialog.ui Resources/UI/ctkSettingsDialog.ui Resources/UI/ctkSliderWidget.ui Resources/UI/ctkThumbnailLabel.ui Resources/UI/ctkThumbnailListWidget.ui Resources/UI/ctkWorkflowGroupBox.ui - Resources/UI/ctkDirectoryListWidget.ui ) # Resources diff --git a/Libs/Widgets/Plugins/CMakeLists.txt b/Libs/Widgets/Plugins/CMakeLists.txt index f36274e0ca..db3d18d80c 100644 --- a/Libs/Widgets/Plugins/CMakeLists.txt +++ b/Libs/Widgets/Plugins/CMakeLists.txt @@ -64,6 +64,10 @@ set(PLUGIN_SRCS ctkModalityWidgetPlugin.h ctkPathLineEditPlugin.cpp ctkPathLineEditPlugin.h + ctkPathListButtonsWidgetPlugin.cpp + ctkPathListButtonsWidgetPlugin.h + ctkPathListWidgetPlugin.cpp + ctkPathListWidgetPlugin.h ctkPopupWidgetPlugin.cpp ctkPopupWidgetPlugin.h ctkRangeSliderPlugin.cpp @@ -120,6 +124,8 @@ set(PLUGIN_MOC_SRCS ctkMenuButtonPlugin.h ctkModalityWidgetPlugin.h ctkPathLineEditPlugin.h + ctkPathListButtonsWidgetPlugin.h + ctkPathListWidgetPlugin.h ctkPopupWidgetPlugin.h ctkRangeSliderPlugin.h ctkRangeWidgetPlugin.h diff --git a/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.cpp b/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.cpp new file mode 100644 index 0000000000..a18bc114a4 --- /dev/null +++ b/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.cpp @@ -0,0 +1,70 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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. + +=========================================================================*/ + +// CTK includes +#include "ctkPathListButtonsWidgetPlugin.h" +#include "ctkPathListButtonsWidget.h" + +//----------------------------------------------------------------------------- +ctkPathListButtonsWidgetPlugin::ctkPathListButtonsWidgetPlugin(QObject* pluginParent) + : QObject(pluginParent) +{ + +} + +//----------------------------------------------------------------------------- +QWidget *ctkPathListButtonsWidgetPlugin::createWidget(QWidget* parentForWidget) +{ + ctkPathListButtonsWidget* newWidget = new ctkPathListButtonsWidget(parentForWidget); + return newWidget; +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidgetPlugin::domXml() const +{ + return "<widget class=\"ctkPathListButtonsWidget\" \ + name=\"PathListButtonsWidget\">\n" + "</widget>\n"; +} + +// -------------------------------------------------------------------------- +QIcon ctkPathListButtonsWidgetPlugin::icon() const +{ + return QIcon(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidgetPlugin::includeFile() const +{ + return "ctkPathListButtonsWidget.h"; +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidgetPlugin::isContainer() const +{ + return false; +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidgetPlugin::name() const +{ + return "ctkPathListButtonsWidget"; +} diff --git a/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.h b/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.h new file mode 100644 index 0000000000..21b86872b2 --- /dev/null +++ b/Libs/Widgets/Plugins/ctkPathListButtonsWidgetPlugin.h @@ -0,0 +1,46 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 __ctkPathListButtonsWidgetPlugin_h +#define __ctkPathListButtonsWidgetPlugin_h + +// CTK includes +#include "ctkWidgetsAbstractPlugin.h" + +class CTK_WIDGETS_PLUGINS_EXPORT ctkPathListButtonsWidgetPlugin : + public QObject, + public ctkWidgetsAbstractPlugin +{ + Q_OBJECT + +public: + ctkPathListButtonsWidgetPlugin(QObject *_parent = 0); + + QWidget *createWidget(QWidget *_parent); + QString domXml() const; + QIcon icon() const; + QString includeFile() const; + bool isContainer() const; + QString name() const; + +}; + +#endif diff --git a/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.cpp b/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.cpp new file mode 100644 index 0000000000..d9a743d9ab --- /dev/null +++ b/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.cpp @@ -0,0 +1,70 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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. + +=========================================================================*/ + +// CTK includes +#include "ctkPathListWidgetPlugin.h" +#include "ctkPathListWidget.h" + +//----------------------------------------------------------------------------- +ctkPathListWidgetPlugin::ctkPathListWidgetPlugin(QObject* pluginParent) + : QObject(pluginParent) +{ + +} + +//----------------------------------------------------------------------------- +QWidget *ctkPathListWidgetPlugin::createWidget(QWidget* parentForWidget) +{ + ctkPathListWidget* newWidget = new ctkPathListWidget(parentForWidget); + return newWidget; +} + +//----------------------------------------------------------------------------- +QString ctkPathListWidgetPlugin::domXml() const +{ + return "<widget class=\"ctkPathListWidget\" \ + name=\"PathListWidget\">\n" + "</widget>\n"; +} + +// -------------------------------------------------------------------------- +QIcon ctkPathListWidgetPlugin::icon() const +{ + return QIcon(":/Icons/listview.png"); +} + +//----------------------------------------------------------------------------- +QString ctkPathListWidgetPlugin::includeFile() const +{ + return "ctkPathListWidget.h"; +} + +//----------------------------------------------------------------------------- +bool ctkPathListWidgetPlugin::isContainer() const +{ + return false; +} + +//----------------------------------------------------------------------------- +QString ctkPathListWidgetPlugin::name() const +{ + return "ctkPathListWidget"; +} diff --git a/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.h b/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.h new file mode 100644 index 0000000000..a72bb66876 --- /dev/null +++ b/Libs/Widgets/Plugins/ctkPathListWidgetPlugin.h @@ -0,0 +1,46 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 __ctkPathListWidgetPlugin_h +#define __ctkPathListWidgetPlugin_h + +// CTK includes +#include "ctkWidgetsAbstractPlugin.h" + +class CTK_WIDGETS_PLUGINS_EXPORT ctkPathListWidgetPlugin : + public QObject, + public ctkWidgetsAbstractPlugin +{ + Q_OBJECT + +public: + ctkPathListWidgetPlugin(QObject *_parent = 0); + + QWidget *createWidget(QWidget *_parent); + QString domXml() const; + QIcon icon() const; + QString includeFile() const; + bool isContainer() const; + QString name() const; + +}; + +#endif diff --git a/Libs/Widgets/Plugins/ctkWidgetsPlugins.h b/Libs/Widgets/Plugins/ctkWidgetsPlugins.h index 77f6d3a0f4..851ca8bf00 100644 --- a/Libs/Widgets/Plugins/ctkWidgetsPlugins.h +++ b/Libs/Widgets/Plugins/ctkWidgetsPlugins.h @@ -50,6 +50,8 @@ #include "ctkMenuButtonPlugin.h" #include "ctkModalityWidgetPlugin.h" #include "ctkPathLineEditPlugin.h" +#include "ctkPathListButtonsWidgetPlugin.h" +#include "ctkPathListWidgetPlugin.h" #include "ctkPopupWidgetPlugin.h" #include "ctkRangeSliderPlugin.h" #include "ctkRangeWidgetPlugin.h" @@ -98,6 +100,8 @@ class CTK_WIDGETS_PLUGINS_EXPORT ctkWidgetsPlugins : public QObject, << new ctkMenuButtonPlugin << new ctkModalityWidgetPlugin << new ctkPathLineEditPlugin + << new ctkPathListButtonsWidgetPlugin + << new ctkPathListWidgetPlugin << new ctkPopupWidgetPlugin << new ctkRangeSliderPlugin << new ctkRangeWidgetPlugin diff --git a/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui b/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui deleted file mode 100644 index 47272f9dae..0000000000 --- a/Libs/Widgets/Resources/UI/ctkDirectoryListWidget.ui +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ctkDirectoryListWidget</class> - <widget class="QWidget" name="ctkDirectoryListWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>435</width> - <height>294</height> - </rect> - </property> - <property name="windowTitle"> - <string>Form</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="ctkDirectoryListView" name="DirectoryList" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - <item> - <widget class="QGroupBox" name="GroupBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="title"> - <string>Paths</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QPushButton" name="AddButton"> - <property name="text"> - <string>Add</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="RemoveButton"> - <property name="text"> - <string>Remove</string> - </property> - </widget> - </item> - <item> - <spacer name="ButtonSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - <item> - <widget class="ctkExpandButton" name="ExpandButton" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>ctkDirectoryListView</class> - <extends>QWidget</extends> - <header>ctkDirectoryListView.h</header> - <container>1</container> - </customwidget> - <customwidget> - <class>ctkExpandButton</class> - <extends>QWidget</extends> - <header>ctkExpandButton.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> diff --git a/Libs/Widgets/Resources/UI/ctkPathListButtonsWidget.ui b/Libs/Widgets/Resources/UI/ctkPathListButtonsWidget.ui new file mode 100644 index 0000000000..487a3c5ca5 --- /dev/null +++ b/Libs/Widgets/Resources/UI/ctkPathListButtonsWidget.ui @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ctkPathListButtonsWidget</class> + <widget class="QWidget" name="ctkPathListButtonsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>302</width> + <height>25</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QToolButton" name="AddFilesButton"> + <property name="toolTip"> + <string>Add files</string> + </property> + <property name="text"> + <string>Add files</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="AddDirectoryButton"> + <property name="toolTip"> + <string>Add a directory</string> + </property> + <property name="text"> + <string>Add directory</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="RemoveButton"> + <property name="toolTip"> + <string>Remove selected entries</string> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="EditButton"> + <property name="toolTip"> + <string>Edit current entry</string> + </property> + <property name="text"> + <string>Edit</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/Libs/Widgets/Testing/Cpp/CMakeLists.txt b/Libs/Widgets/Testing/Cpp/CMakeLists.txt index df1bb56db2..73a27153fd 100644 --- a/Libs/Widgets/Testing/Cpp/CMakeLists.txt +++ b/Libs/Widgets/Testing/Cpp/CMakeLists.txt @@ -50,6 +50,8 @@ set(TEST_SOURCES ctkMessageBoxDontShowAgainTest.cpp ctkModalityWidgetTest1.cpp ctkPathLineEditTest1.cpp + ctkPathListWidgetTest.cpp + ctkPathListWidgetWithButtonsTest.cpp ctkPopupWidgetTest1.cpp ctkRangeSliderTest.cpp ctkRangeSliderTest1.cpp @@ -173,6 +175,8 @@ QT4_GENERATE_MOCS( ctkFlatProxyModelTest.cpp ctkFontButtonTest.cpp ctkMessageBoxDontShowAgainTest.cpp + ctkPathListWidgetTest.cpp + ctkPathListWidgetWithButtonsTest.cpp ctkRangeSliderTest.cpp ctkSettingsPanelTest.cpp ) @@ -242,6 +246,8 @@ SIMPLE_TEST( ctkMenuComboBoxTest3 ) SIMPLE_TEST( ctkMessageBoxDontShowAgainTest ) SIMPLE_TEST( ctkModalityWidgetTest1 ) SIMPLE_TEST( ctkPathLineEditTest1 ) +SIMPLE_TEST( ctkPathListWidgetTest ) +SIMPLE_TEST( ctkPathListWidgetWithButtonsTest ) SIMPLE_TEST( ctkPopupWidgetTest1 ) SIMPLE_TEST( ctkRangeSliderTest ) SIMPLE_TEST( ctkRangeSliderTest1 ) diff --git a/Libs/Widgets/Testing/Cpp/ctkPathListWidgetTest.cpp b/Libs/Widgets/Testing/Cpp/ctkPathListWidgetTest.cpp new file mode 100644 index 0000000000..f9b0b83d15 --- /dev/null +++ b/Libs/Widgets/Testing/Cpp/ctkPathListWidgetTest.cpp @@ -0,0 +1,307 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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. + +=========================================================================*/ + +// Qt includes +#include <QCoreApplication> +#include <QSignalSpy> +#include <QTimer> + +// CTK includes +#include "ctkPathListWidget.h" +#include "ctkTest.h" + +// STD includes +#include <cstdlib> +#include <iostream> + +//----------------------------------------------------------------------------- +class ctkPathListWidgetTester : public QObject +{ + Q_OBJECT + +private slots: + + void testDefaults(); + void testChangeOptions(); + void testMode(); + void testRelativeAndAbsolutePaths(); + void testSimilarPaths(); + void testSetPaths(); + void testEditPaths(); +}; + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testDefaults() +{ + ctkPathListWidget pathList; + + QSignalSpy pathListChangedSpy(&pathList, SIGNAL(pathsChanged(QStringList,QStringList))); + + // The default options are Readable and Exists + + QCOMPARE(pathList.fileOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable); + QCOMPARE(pathList.directoryOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable); + + QVERIFY(!pathList.addPath("/shouldnotexist/")); + QVERIFY(!pathList.addPath("/should/also/not/exist")); + + QVERIFY(pathList.addPath(QDir::tempPath())); + QVERIFY(!pathList.addPath(QDir::tempPath())); + + QVERIFY(!pathList.removePath("/shouldnotexist/")); + + + QList<QVariant> expectedArgs; + expectedArgs.push_back(QStringList(QDir::tempPath())); + expectedArgs.push_back(QStringList()); + + QCOMPARE(pathList.paths(), expectedArgs.front().toStringList()); + + QCOMPARE(pathListChangedSpy.count(), 1); + QCOMPARE(pathListChangedSpy.front(), expectedArgs); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testChangeOptions() +{ + ctkPathListWidget pathList; + + QSignalSpy pathListChangedSpy(&pathList, SIGNAL(pathsChanged(QStringList,QStringList))); + + // The default options are Readable and Exists + + QCOMPARE(pathList.fileOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable); + QCOMPARE(pathList.directoryOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable); + + QCOMPARE(pathList.mode(), ctkPathListWidget::Any); + + QTemporaryFile tmpFile; + QVERIFY(tmpFile.open()); + + QVERIFY(!tmpFile.permissions().testFlag(QFile::ExeOwner)); + + QVERIFY(pathList.addPath(tmpFile.fileName())); + QCOMPARE(pathList.path(0), tmpFile.fileName()); + pathList.clear(); + QCOMPARE(pathList.count(), 0); + QCOMPARE(pathList.path(0), QString()); + + QCOMPARE(pathListChangedSpy.size(), 2); + QCOMPARE(pathListChangedSpy.at(0), QList<QVariant>() << (QStringList() << tmpFile.fileName()) << QStringList()); + QCOMPARE(pathListChangedSpy.at(1), QList<QVariant>() << QStringList() << (QStringList() << tmpFile.fileName())); + + pathListChangedSpy.clear(); + + // Add another temporary non-executable file + QTemporaryFile tmpFile2; + QVERIFY(tmpFile2.open()); + QVERIFY(pathList.addPath(tmpFile2.fileName())); + QCOMPARE(pathList.count(), 1); + QCOMPARE(pathList.path(0), tmpFile2.fileName()); + + pathListChangedSpy.clear(); + + // Changing the file options. This should invalidate tmpFile2 and remove it + pathList.setFileOptions(pathList.fileOptions() | ctkPathListWidget::Executable); + QCOMPARE(pathList.fileOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable | ctkPathListWidget::Executable); + pathList.setDirectoryOptions(pathList.directoryOptions() | ctkPathListWidget::Writable); + QCOMPARE(pathList.directoryOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable | ctkPathListWidget::Writable); + + QCOMPARE(pathList.count(), 0); + + QCOMPARE(pathListChangedSpy.count(), 1); + QCOMPARE(pathListChangedSpy.at(0), QList<QVariant>() << QStringList() << (QStringList() << tmpFile2.fileName())); + pathListChangedSpy.clear(); + + // The tmp file is not executable, so it should not be added now + QVERIFY(!pathList.addPath(tmpFile.fileName())); + QVERIFY(pathListChangedSpy.isEmpty()); + + QVERIFY(tmpFile.setPermissions(tmpFile.permissions() | QFile::ExeOwner)); + + // Try again + QVERIFY(pathList.addPath(tmpFile.fileName())); + QCOMPARE(pathList.count(), 1); + QCOMPARE(pathList.path(0), tmpFile.fileName()); + + // Change the file options again. This should not invalidate the executable temporary file + pathList.setFileOptions(ctkPathListWidget::Exists | ctkPathListWidget::Readable); + QCOMPARE(pathList.fileOptions(), ctkPathListWidget::Exists | ctkPathListWidget::Readable); + QCOMPARE(pathList.paths(), QStringList() << tmpFile.fileName()); + + // Add the non-executable tmpFile2 again + pathList.addPath(tmpFile2.fileName()); + QCOMPARE(pathList.count(), 2); + QCOMPARE(pathList.paths(), QStringList() << tmpFile.fileName() << tmpFile2.fileName()); + + QCOMPARE(pathListChangedSpy.count(), 2); + pathListChangedSpy.clear(); + + // Remove all + pathList.clear(); + QCOMPARE(pathList.count(), 0); + QCOMPARE(pathListChangedSpy.count(), 1); + QCOMPARE(pathListChangedSpy.at(0), QList<QVariant>() << QStringList() + << (QStringList() << tmpFile.fileName() << tmpFile2.fileName())); + pathListChangedSpy.clear(); + + // Add two at once + pathList.addPaths(QStringList() << tmpFile.fileName() << tmpFile2.fileName()); + QCOMPARE(pathList.count(), 2); + QCOMPARE(pathList.path(0), tmpFile.fileName()); + QCOMPARE(pathList.path(1), tmpFile2.fileName()); + + QCOMPARE(pathListChangedSpy.count(), 1); + QCOMPARE(pathListChangedSpy.at(0), QList<QVariant>() + << (QStringList() << tmpFile.fileName() << tmpFile2.fileName()) + << QStringList()); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testMode() +{ + ctkPathListWidget listWidget; + + listWidget.setFileOptions(ctkPathListWidget::None); + QVERIFY(listWidget.fileOptions() == ctkPathListWidget::None); + listWidget.setDirectoryOptions(ctkPathListWidget::None); + QVERIFY(listWidget.directoryOptions() == ctkPathListWidget::None); + + QVERIFY(listWidget.addPath("/a")); + QVERIFY(listWidget.addPath("/a/")); + + listWidget.setMode(ctkPathListWidget::FilesOnly); + QVERIFY(listWidget.addPath("/b")); + QVERIFY(!listWidget.addPath("/b/")); + + listWidget.setMode(ctkPathListWidget::DirectoriesOnly); + QVERIFY(!listWidget.addPath("/c")); + QVERIFY(listWidget.addPath("/c/")); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testRelativeAndAbsolutePaths() +{ + ctkPathListWidget listWidget; + + listWidget.setFileOptions(ctkPathListWidget::None); + QVERIFY(listWidget.fileOptions() == ctkPathListWidget::None); + listWidget.setDirectoryOptions(ctkPathListWidget::None); + QVERIFY(listWidget.directoryOptions() == ctkPathListWidget::None); + + QStringList paths = QStringList() + << "/some/absolute/path/to/file" + << "/some/absolute/path/to/dir/" + << "relative/path/to/file" + << "relative/path/to/dir/"; + + QStringList resultPaths = QStringList() + << "/some/absolute/path/to/file" + << "/some/absolute/path/to/dir/" + << QDir::currentPath() + "/relative/path/to/file" + << QDir::currentPath() + "/relative/path/to/dir/"; + + QCOMPARE(listWidget.addPaths(paths), resultPaths); + + QCOMPARE(listWidget.path(0), resultPaths[0]); + QCOMPARE(listWidget.path(1), resultPaths[1]); + QCOMPARE(listWidget.path(2), resultPaths[2]); + QCOMPARE(listWidget.path(3), resultPaths[3]); + + QCOMPARE(listWidget.files(), QStringList() << paths[0] << paths[2]); + QCOMPARE(listWidget.files(true), QStringList() << resultPaths[0] << resultPaths[2]); + QCOMPARE(listWidget.directories(), QStringList() << paths[1] << paths[3]); + QCOMPARE(listWidget.directories(true), QStringList() << resultPaths[1] << resultPaths[3]); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testSimilarPaths() +{ + ctkPathListWidget listWidget; + + listWidget.setFileOptions(ctkPathListWidget::None); + listWidget.setDirectoryOptions(ctkPathListWidget::None); + + QVERIFY(listWidget.addPath("/one/path")); + QVERIFY(listWidget.addPath("/one/path/")); + QVERIFY(listWidget.addPath("/one")); + QVERIFY(listWidget.addPath("/one/")); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testSetPaths() +{ + ctkPathListWidget listWidget; + + listWidget.setFileOptions(ctkPathListWidget::None); + QVERIFY(listWidget.fileOptions() == ctkPathListWidget::None); + listWidget.setDirectoryOptions(ctkPathListWidget::None); + QVERIFY(listWidget.directoryOptions() == ctkPathListWidget::None); + + QVERIFY(listWidget.addPath("/file/a")); + QVERIFY(listWidget.addPath("/file/b")); + QVERIFY(listWidget.addPath("/dir/a/")); + + QSignalSpy pathListChangedSpy(&listWidget, SIGNAL(pathsChanged(QStringList,QStringList))); + + QStringList newPaths = QStringList() + << "/new/file/x" + << "/file/b" + << "/new/dir/x"; + + listWidget.setPaths(newPaths); + QCOMPARE(pathListChangedSpy.count(), 1); + QCOMPARE(pathListChangedSpy.front().at(0).toStringList(), QStringList() << "/new/file/x" << "/new/dir/x"); +} + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetTester::testEditPaths() +{ + ctkPathListWidget listWidget; + + listWidget.setFileOptions(ctkPathListWidget::None); + listWidget.setDirectoryOptions(ctkPathListWidget::None); + + QVERIFY(listWidget.addPath("/file/a")); + QVERIFY(listWidget.addPath("/file/b")); + QVERIFY(listWidget.addPath("/dir/a/")); + + QSignalSpy pathListChangedSpy(&listWidget, SIGNAL(pathsChanged(QStringList,QStringList))); + + QVERIFY(!listWidget.editPath(QModelIndex(), "bla")); + QVERIFY(!listWidget.editPath(listWidget.model()->index(0,0), "/new/file/a/")); + QVERIFY(listWidget.editPath(listWidget.model()->index(0,0), "/new/file/a")); + QCOMPARE(listWidget.path(0), QString("/new/file/a")); + + QVERIFY(listWidget.editPath("/dir/a/", "/new/dir/a/")); + QCOMPARE(listWidget.path(2), QString("/new/dir/a/")); + + QCOMPARE(pathListChangedSpy.count(), 2); + QCOMPARE(pathListChangedSpy.at(0).at(0).toString(), QString("/new/file/a")); + QCOMPARE(pathListChangedSpy.at(0).at(1).toString(), QString("/file/a")); + + QCOMPARE(pathListChangedSpy.at(1).at(0).toString(), QString("/new/dir/a/")); + QCOMPARE(pathListChangedSpy.at(1).at(1).toString(), QString("/dir/a/")); +} + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkPathListWidgetTest) +#include "moc_ctkPathListWidgetTest.cpp" diff --git a/Libs/Widgets/Testing/Cpp/ctkPathListWidgetWithButtonsTest.cpp b/Libs/Widgets/Testing/Cpp/ctkPathListWidgetWithButtonsTest.cpp new file mode 100644 index 0000000000..1c0dc3d1ca --- /dev/null +++ b/Libs/Widgets/Testing/Cpp/ctkPathListWidgetWithButtonsTest.cpp @@ -0,0 +1,99 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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. + +=========================================================================*/ + +// Qt includes +#include <QApplication> +#include <QWidget> +#include <QHBoxLayout> +#include <QTimer> +#include <QToolButton> + +// CTK includes +#include "ctkPathListWidget.h" +#include "ctkPathListButtonsWidget.h" +#include "ctkUtils.h" +#include "ctkTest.h" + +// STD includes +#include <cstdlib> +#include <iostream> + +//----------------------------------------------------------------------------- +class ctkPathListWidgetWithButtonsTester : public QObject +{ + Q_OBJECT + +private slots: + + void testButtons(); + +}; + +// ---------------------------------------------------------------------------- +void ctkPathListWidgetWithButtonsTester::testButtons() +{ + QWidget topLevel; + topLevel.setLayout(new QHBoxLayout()); + + ctkPathListWidget pathList(&topLevel); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sizePolicy.setHorizontalStretch(1); + pathList.setSizePolicy(sizePolicy); + + ctkPathListButtonsWidget pathListButtons(&topLevel); + pathListButtons.init(&pathList); + pathListButtons.setOrientation(Qt::Vertical); + + + topLevel.layout()->addWidget(&pathList); + topLevel.layout()->addWidget(&pathListButtons); + + topLevel.show(); + QTest::qWaitForWindowShown(&topLevel); + + struct CloseModalDialog : public QRunnable + { + void run() + { + QTest::qWait(1000); + QTimer::singleShot(0, QApplication::activeModalWidget(), SLOT(accept())); + } + }; + QThreadPool::globalInstance()->start(new CloseModalDialog); + QTest::mouseClick(pathListButtons.buttonAddDirectory(), Qt::LeftButton); + + QCOMPARE(pathList.count(), 1); + QVERIFY(!pathListButtons.buttonRemove()->isEnabled()); + QVERIFY(!pathListButtons.buttonEdit()->isEnabled()); + + pathList.selectAll(); + + QVERIFY(pathListButtons.buttonRemove()->isEnabled()); + QVERIFY(pathListButtons.buttonEdit()->isEnabled()); + + QTest::mouseClick(pathListButtons.buttonRemove(), Qt::LeftButton); + QCOMPARE(pathList.count(), 0); +} + + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkPathListWidgetWithButtonsTest) +#include "moc_ctkPathListWidgetWithButtonsTest.cpp" diff --git a/Libs/Widgets/ctkDirectoryListView.cpp b/Libs/Widgets/ctkDirectoryListView.cpp deleted file mode 100644 index 0a091f1804..0000000000 --- a/Libs/Widgets/ctkDirectoryListView.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/*========================================================================= - - Library: CTK - - Copyright (c) Kitware Inc. - - 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. - - This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. - and was partially funded by NIH grant 3P41RR013218-12S1 - -=========================================================================*/ - -// Qt includes -#include <QFileInfo> -#include <QHBoxLayout> -#include <QListView> -#include <QStandardItemModel> - -// QtGUI includes -#include "ctkDirectoryListView.h" - -// -------------------------------------------------------------------------- -// ctkDirectoryListViewPrivate - -//----------------------------------------------------------------------------- -class ctkDirectoryListViewPrivate -{ - Q_DECLARE_PUBLIC(ctkDirectoryListView); -protected: - ctkDirectoryListView* const q_ptr; - -public: - ctkDirectoryListViewPrivate(ctkDirectoryListView& object); - void init(); - - void addDirectory(const QString& path); - - enum - { - AbsolutePathRole = Qt::UserRole + 1 - }; - - QListView* ListView; - QStandardItemModel DirectoryListModel; -}; - -// -------------------------------------------------------------------------- -// ctkDirectoryListViewPrivate methods - -// -------------------------------------------------------------------------- -ctkDirectoryListViewPrivate::ctkDirectoryListViewPrivate(ctkDirectoryListView& object) - :q_ptr(&object) -{ -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListViewPrivate::init() -{ - Q_Q(ctkDirectoryListView); - - this->ListView = new QListView(); - this->ListView->setSelectionBehavior(QAbstractItemView::SelectRows); - this->ListView->setSelectionMode(QAbstractItemView::ExtendedSelection); - this->ListView->setEditTriggers(QAbstractItemView::NoEditTriggers); - QHBoxLayout * layout = new QHBoxLayout(); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(this->ListView); - q->setLayout(layout); - - this->ListView->setModel(&this->DirectoryListModel); -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListViewPrivate::addDirectory(const QString& path) -{ - Q_Q(ctkDirectoryListView); - QString absolutePath = QFileInfo(path).absoluteFilePath(); - if (!QFile::exists(absolutePath) || q->hasDirectory(absolutePath)) - { - return; - } - QStandardItem * item = new QStandardItem(path); - item->setData(QVariant(absolutePath), Qt::ToolTipRole); - item->setData(QVariant(absolutePath), ctkDirectoryListViewPrivate::AbsolutePathRole); - this->DirectoryListModel.appendRow(item); -} - -// -------------------------------------------------------------------------- -// ctkDirectoryListView methods - -// -------------------------------------------------------------------------- -ctkDirectoryListView::ctkDirectoryListView(QWidget* _parent) - : Superclass(_parent) - , d_ptr(new ctkDirectoryListViewPrivate(*this)) -{ - Q_D(ctkDirectoryListView); - d->init(); -} - -// -------------------------------------------------------------------------- -ctkDirectoryListView::~ctkDirectoryListView() -{ -} - -// -------------------------------------------------------------------------- -QStringList ctkDirectoryListView::directoryList(bool absolutePath)const -{ - Q_D(const ctkDirectoryListView); - QStringList directoryList; - int role = Qt::DisplayRole; - if (absolutePath) - { - role = ctkDirectoryListViewPrivate::AbsolutePathRole; - } - for(int i = 0; i < d->DirectoryListModel.rowCount(); ++i) - { - directoryList << d->DirectoryListModel.data(d->DirectoryListModel.index(i, 0), role).toString(); - } - return directoryList; -} - -// -------------------------------------------------------------------------- -QStringList ctkDirectoryListView::selectedDirectoryList(bool absolutePath)const -{ - Q_D(const ctkDirectoryListView); - QStringList directoryList; - int role = Qt::DisplayRole; - if (absolutePath) - { - role = ctkDirectoryListViewPrivate::AbsolutePathRole; - } - QModelIndexList selectedIndexes = d->ListView->selectionModel()->selectedRows(); - foreach(const QModelIndex& index, selectedIndexes) - { - directoryList << d->DirectoryListModel.data(index, role).toString(); - } - return directoryList; -} - -// -------------------------------------------------------------------------- -bool ctkDirectoryListView::hasDirectory(const QString& path)const -{ - Q_D(const ctkDirectoryListView); - QString absolutePath = QFileInfo(path).absoluteFilePath(); - QModelIndexList foundIndexes = d->DirectoryListModel.match( - d->DirectoryListModel.index(0, 0), ctkDirectoryListViewPrivate::AbsolutePathRole, - QVariant(absolutePath)); - Q_ASSERT(foundIndexes.size() < 2); - return (foundIndexes.size() != 0); -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::addDirectory(const QString& path) -{ - Q_D(ctkDirectoryListView); - d->addDirectory(path); - emit this->directoryListChanged(); -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::removeDirectory(const QString& path) -{ - Q_D(ctkDirectoryListView); - QList<QStandardItem*> foundItems = d->DirectoryListModel.findItems(path); - Q_ASSERT(foundItems.count() < 2); - if (foundItems.count() == 1) - { - d->DirectoryListModel.removeRow(foundItems.at(0)->row()); - emit this->directoryListChanged(); - } -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::removeSelectedDirectories() -{ - Q_D(ctkDirectoryListView); - - QModelIndexList selectedIndexes = d->ListView->selectionModel()->selectedRows(); - bool selectedCount = selectedIndexes.count(); - while(selectedIndexes.count() > 0) - { - d->DirectoryListModel.removeRow(selectedIndexes.at(0).row()); - selectedIndexes = d->ListView->selectionModel()->selectedRows(); - } - if (selectedCount) - { - emit this->directoryListChanged(); - } -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::selectAllDirectories() -{ - Q_D(ctkDirectoryListView); - d->ListView->selectAll(); -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::clearDirectorySelection() -{ - Q_D(ctkDirectoryListView); - d->ListView->clearSelection(); -} - -// -------------------------------------------------------------------------- -void ctkDirectoryListView::setDirectoryList(const QStringList& paths) -{ - Q_D(ctkDirectoryListView); - - if (paths.count() == this->directoryList().count()) - { - int found = 0; - foreach(const QString& path, paths) - { - if (this->hasDirectory(path)) - { - ++found; - } - } - if (found == paths.count()) - { - return; - } - } - - d->DirectoryListModel.removeRows(0, d->DirectoryListModel.rowCount()); - - foreach(const QString& path, paths) - { - d->addDirectory(path); - } - emit this->directoryListChanged(); -} - diff --git a/Libs/Widgets/ctkDirectoryListView.h b/Libs/Widgets/ctkDirectoryListView.h deleted file mode 100644 index 97f8b8d88d..0000000000 --- a/Libs/Widgets/ctkDirectoryListView.h +++ /dev/null @@ -1,96 +0,0 @@ -/*========================================================================= - - Library: CTK - - Copyright (c) Kitware Inc. - - 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. - - This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. - and was partially funded by NIH grant 3P41RR013218-12S1 - -=========================================================================*/ - -#ifndef __ctkDirectoryListView_h -#define __ctkDirectoryListView_h - -// Qt includes -#include <QWidget> - -// QtGUI includes -#include "ctkWidgetsExport.h" - -class ctkDirectoryListViewPrivate; - -class CTK_WIDGETS_EXPORT ctkDirectoryListView : public QWidget -{ - Q_OBJECT - Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList NOTIFY directoryListChanged); -public: - /// Superclass typedef - typedef QWidget Superclass; - - /// Constructor - explicit ctkDirectoryListView(QWidget* parent = 0); - - /// Destructor - virtual ~ctkDirectoryListView(); - - /// Return True if the \a path has already been added - bool hasDirectory(const QString& path)const; - - QStringList directoryList(bool absolutePath = false)const; - - QStringList selectedDirectoryList(bool absolutePath = false)const; - -public slots: - - /// If \a path exists, add it to the view and emit signal directoryListChanged(). - /// \sa directoryListChanged() - void addDirectory(const QString& path); - - /// Remove all entries and set \a paths has current list. - /// The signal directoryListChanged() is emitted if the current list of directories is - /// different from the provided one. - /// \sa addDirectory(), directoryListChanged() - void setDirectoryList(const QStringList& paths); - - /// Remove \a path from the list. - /// The signal directoryListChanged() is emitted if the path was in the list. - /// \sa directoryListChanged() - void removeDirectory(const QString& path); - - /// \sa selectAllDirectories() - void removeSelectedDirectories(); - - /// Select all directories. - void selectAllDirectories(); - - /// Clear the current directory selection. - void clearDirectorySelection(); - -signals: - /// This signal is emitted when a directory is added to the view. - void directoryListChanged(); - -protected: - QScopedPointer<ctkDirectoryListViewPrivate> d_ptr; - -private: - Q_DECLARE_PRIVATE(ctkDirectoryListView); - Q_DISABLE_COPY(ctkDirectoryListView); - -}; - -#endif - diff --git a/Libs/Widgets/ctkDirectoryListWidget.cpp b/Libs/Widgets/ctkDirectoryListWidget.cpp deleted file mode 100644 index 76b6ae8ba8..0000000000 --- a/Libs/Widgets/ctkDirectoryListWidget.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/*========================================================================= - - Library: CTK - - Copyright (c) University College London. - - 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. - -=========================================================================*/ - -#include <iostream> - -// Qt includes -#include <QDebug> -#include <QFileDialog> - -// CTK includes -#include "ctkDirectoryListWidget.h" -#include "ctkDirectoryListWidget_p.h" - -//----------------------------------------------------------------------------- -// ctkDirectoryListWidgetPrivate methods - -//----------------------------------------------------------------------------- -ctkDirectoryListWidgetPrivate::~ctkDirectoryListWidgetPrivate() -{ -} - -//----------------------------------------------------------------------------- -ctkDirectoryListWidgetPrivate::ctkDirectoryListWidgetPrivate(ctkDirectoryListWidget& object) - : QObject(&object), q_ptr(&object) -{ -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::init() -{ - Q_Q(ctkDirectoryListWidget); - this->setupUi(q); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::setupUi(QWidget * widget) -{ - this->Ui_ctkDirectoryListWidget::setupUi(widget); - - this->ExpandButton->setChecked(false); - this->ExpandButton->setMirrorOnExpand(true); - this->GroupBox->hide(); - - QObject::connect(this->AddButton, SIGNAL(clicked()), - this, SLOT(onAddClicked())); - QObject::connect(this->RemoveButton, SIGNAL(clicked()), - this, SLOT(onRemoveClicked())); - QObject::connect(this->ExpandButton, SIGNAL(clicked(bool)), - this, SLOT(onExpandClicked(bool))); - QObject::connect(this->DirectoryList, SIGNAL(directoryListChanged()), - this, SLOT(onDirectoryListChanged())); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::setDirectoryList(const QStringList& list) -{ - this->DirectoryList->setDirectoryList(list); -} - -//----------------------------------------------------------------------------- -QStringList ctkDirectoryListWidgetPrivate::directoryList() const -{ - return this->DirectoryList->directoryList(true); // true for absolute path. -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::onAddClicked() -{ - QString path = QFileDialog::getExistingDirectory( - this->DirectoryList, tr("Select folder"), - QString("")); - // An empty directory means that the user cancelled the dialog. - if (path.isEmpty()) - { - return; - } - this->DirectoryList->addDirectory(path); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::onRemoveClicked() -{ - this->DirectoryList->removeSelectedDirectories(); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::onExpandClicked(bool state) -{ - this->GroupBox->setVisible(state); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidgetPrivate::onDirectoryListChanged() -{ - Q_Q(ctkDirectoryListWidget); - emit (q->directoryListChanged(this->DirectoryList->directoryList())); -} - -//----------------------------------------------------------------------------- -// ctkDirectoryListWidget methods - -//----------------------------------------------------------------------------- -ctkDirectoryListWidget::~ctkDirectoryListWidget() -{ -} - -//----------------------------------------------------------------------------- -ctkDirectoryListWidget::ctkDirectoryListWidget(QWidget* newParent) - : Superclass(newParent) - , d_ptr(new ctkDirectoryListWidgetPrivate(*this)) -{ - Q_D(ctkDirectoryListWidget); - d->init(); -} - -//----------------------------------------------------------------------------- -void ctkDirectoryListWidget::setDirectoryList(const QStringList& list) -{ - Q_D(ctkDirectoryListWidget); - d->setDirectoryList(list); -} - -//----------------------------------------------------------------------------- -QStringList ctkDirectoryListWidget::directoryList() const -{ - Q_D(const ctkDirectoryListWidget); - return d->directoryList(); -} - diff --git a/Libs/Widgets/ctkDirectoryListWidget.h b/Libs/Widgets/ctkDirectoryListWidget.h deleted file mode 100644 index d7cb992844..0000000000 --- a/Libs/Widgets/ctkDirectoryListWidget.h +++ /dev/null @@ -1,69 +0,0 @@ -/*========================================================================= - - Library: CTK - - Copyright (c) University College London. - - 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 __ctkDirectoryListWidget_h -#define __ctkDirectoryListWidget_h - -// Qt includes -#include <QWidget> -#include <QStringList> - -// QtGUI includes -#include "ctkWidgetsExport.h" - -class ctkDirectoryListWidgetPrivate; - -/** - * \class ctkDirectoryListWidget - * \brief A widget to maintain a list of directories, with add and remove buttons, - * such as might be used in a settings panel to select a series of directories to search. - * - * \author m.clarkson@ucl.ac.uk - */ -class CTK_WIDGETS_EXPORT ctkDirectoryListWidget : public QWidget -{ - Q_OBJECT - Q_PROPERTY(QStringList directoryList READ directoryList WRITE setDirectoryList) - -public: - /// Superclass typedef - typedef QWidget Superclass; - ctkDirectoryListWidget(QWidget* parent = 0); - virtual ~ctkDirectoryListWidget(); - - /// Set the directory list, which will overwrite any existing list. - void setDirectoryList(const QStringList& list); - QStringList directoryList() const; - -public Q_SLOTS: - -Q_SIGNALS: - /// directoryListChanged emmitted whenever the list of directories is changed. - void directoryListChanged(const QStringList& directories); - -protected: - QScopedPointer<ctkDirectoryListWidgetPrivate> d_ptr; - -private: - Q_DECLARE_PRIVATE(ctkDirectoryListWidget); - Q_DISABLE_COPY(ctkDirectoryListWidget); -}; - -#endif diff --git a/Libs/Widgets/ctkPathListButtonsWidget.cpp b/Libs/Widgets/ctkPathListButtonsWidget.cpp new file mode 100644 index 0000000000..d591d79b4d --- /dev/null +++ b/Libs/Widgets/ctkPathListButtonsWidget.cpp @@ -0,0 +1,713 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) University College London. + + 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. + +=========================================================================*/ + +#include <iostream> + +// Qt includes +#include <QDebug> +#include <QFileDialog> +#include <QSortFilterProxyModel> +#include <QFileSystemModel> +#include <QFileInfo> +#include <QMessageBox> + +// CTK includes +#include "ctkPathListButtonsWidget.h" +#include "ctkPathListButtonsWidget_p.h" + +//----------------------------------------------------------------------------- +// ctkPathListButtonsWidgetPrivate methods + +//----------------------------------------------------------------------------- +ctkPathListButtonsWidgetPrivate::~ctkPathListButtonsWidgetPrivate() +{ +} + +//----------------------------------------------------------------------------- +ctkPathListButtonsWidgetPrivate::ctkPathListButtonsWidgetPrivate(ctkPathListButtonsWidget& object) + : QObject(&object) + , q_ptr(&object) + , PathListWidget(NULL) +{ +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::init() +{ + Q_Q(ctkPathListButtonsWidget); + this->setupUi(q); + + q->unsetIconAddFilesButton(); + q->unsetIconAddDirectoryButton(); + q->unsetIconRemoveButton(); + q->unsetIconEditButton(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::setupUi(QWidget * widget) +{ + this->Ui_ctkPathListButtonsWidget::setupUi(widget); + + connect(this->AddFilesButton, SIGNAL(clicked()), SLOT(on_AddFilesButton_clicked())); + connect(this->AddDirectoryButton, SIGNAL(clicked()), SLOT(on_AddDirButton_clicked())); + connect(this->RemoveButton, SIGNAL(clicked()), SLOT(on_RemoveButton_clicked())); + connect(this->EditButton, SIGNAL(clicked()), SLOT(on_EditButton_clicked())); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::on_AddFilesButton_clicked() +{ + if (!this->PathListWidget) return; + + QStringList paths = this->openAddFilesDialog(true); + this->addPathsWithWarningMessage(paths); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::on_AddDirButton_clicked() +{ + if (!this->PathListWidget) return; + + QStringList paths = this->openAddDirDialog(); + this->addPathsWithWarningMessage(paths); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::on_RemoveButton_clicked() +{ + if (!this->PathListWidget) return; + + this->PathListWidget->removeSelectedPaths(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::on_EditButton_clicked() +{ + Q_Q(ctkPathListButtonsWidget); + + if (!this->PathListWidget) return; + + QString currentPath = this->PathListWidget->currentPath(true); + + QStringList paths; + if (this->PathListWidget->isFile(currentPath)) + { + paths = this->openAddFilesDialog(false); + } + else + { + paths = this->openAddDirDialog(); + } + + if (!paths.isEmpty()) + { + if (!this->PathListWidget->editPath(currentPath, paths.front())) + { + QMessageBox::information(q, tr("Editing the path failed"), + QString(tr("Failed to change path:\n\n%1\n\nto path\n\n%2\n\nPlease check your permissions.")) + .arg(currentPath).arg(paths.front())); + } + } +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::on_PathListWidget_selectionChanged(const QItemSelection &selected, + const QItemSelection &deselected) +{ + Q_UNUSED(selected) + Q_UNUSED(deselected) + + bool hasSelection = this->PathListWidget->selectionModel()->hasSelection(); + this->EditButton->setEnabled(hasSelection); + this->RemoveButton->setEnabled(hasSelection); +} + +//----------------------------------------------------------------------------- +QStringList ctkPathListButtonsWidgetPrivate::openAddFilesDialog(bool multiple) +{ + Q_Q(ctkPathListButtonsWidget); + + if (!this->PathListWidget) return QStringList(); + + QString caption; + if (multiple) + { + caption = tr("Select one or more files"); + } + else + { + caption = tr("Select a file"); + } + + QFileDialog fileDialog(q, caption); + fileDialog.setReadOnly(true); + + if (multiple) + { + fileDialog.setFileMode(QFileDialog::ExistingFiles); + } + else + { + fileDialog.setFileMode(QFileDialog::ExistingFile); + } + + QString currentPath = this->PathListWidget->currentPath(true); + currentPath = currentPath.left(currentPath.lastIndexOf('/') + 1); + if (!currentPath.isEmpty()) + { + fileDialog.setDirectory(currentPath); + } + + // We use a proxy model as a workaround for the broken QFileDialog::setFilter() method. + // See for example https://bugreports.qt-project.org/browse/QTBUG-10244 + class FileFilterProxyModel : public QSortFilterProxyModel + { + public: + FileFilterProxyModel(ctkPathListWidget::PathOptions fileOptions) + : FileOptions(fileOptions) + {} + + protected: + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const + { + QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); + QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel()); + + QFileInfo fileInfo = fileModel->fileInfo(sourceIndex); + + if(fileInfo.isFile()) + { + if (FileOptions.testFlag(ctkPathListWidget::Readable) && + !fileInfo.isReadable()) + { + return false; + } + if (FileOptions.testFlag(ctkPathListWidget::Writable) && + !fileInfo.isWritable()) + { + return false; + } + if (FileOptions.testFlag(ctkPathListWidget::Executable)&& + !fileInfo.isExecutable()) + { + return false; + } + return true; + } + else + { + // Show all readable directories + return fileInfo.isReadable(); + } + } + + private: + ctkPathListWidget::PathOptions FileOptions; + }; + + fileDialog.setProxyModel(new FileFilterProxyModel(this->PathListWidget->fileOptions())); + + if (fileDialog.exec() == QDialog::Accepted) + { + return fileDialog.selectedFiles(); + } + return QStringList(); +} + +//----------------------------------------------------------------------------- +QStringList ctkPathListButtonsWidgetPrivate::openAddDirDialog() +{ + Q_Q(ctkPathListButtonsWidget); + + if (!this->PathListWidget) return QStringList(); + + QString caption = tr("Select a directory"); + QFileDialog fileDialog(q, caption); + + fileDialog.setFileMode(QFileDialog::Directory); + fileDialog.setOption(QFileDialog::ShowDirsOnly); + + QString currentPath = this->PathListWidget->currentPath(true); + if (!currentPath.isEmpty()) + { + fileDialog.setDirectory(currentPath); + } + + // We use a proxy model as a workaround for the broken QFileDialog::setFilter() method. + // See for example https://bugreports.qt-project.org/browse/QTBUG-10244 + class DirFilterProxyModel : public QSortFilterProxyModel + { + public: + DirFilterProxyModel(ctkPathListWidget::PathOptions dirOptions) + : DirOptions(dirOptions) + {} + + protected: + virtual bool filterAcceptsRow(int sourceRow, const QModelIndex & sourceParent) const + { + QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); + QFileSystemModel* fileModel = qobject_cast<QFileSystemModel*>(sourceModel()); + + QFileInfo fileInfo = fileModel->fileInfo(sourceIndex); + + if (DirOptions.testFlag(ctkPathListWidget::Readable) && + !fileInfo.isReadable()) + { + return false; + } + // Do not check for the Writable flag, since it makes navigation from + // non-writable folders to writable sub-folders hard. +// if (DirOptions.testFlag(ctkPathListWidget::Writable) && +// !fileInfo.isWritable()) +// { +// return false; +// } + return true; + } + + private: + ctkPathListWidget::PathOptions DirOptions; + }; + + fileDialog.setProxyModel(new DirFilterProxyModel(this->PathListWidget->directoryOptions())); + + if (fileDialog.exec() == QDialog::Accepted) + { + return fileDialog.selectedFiles(); + } + return QStringList(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidgetPrivate::addPathsWithWarningMessage(const QStringList& paths) +{ + Q_Q(ctkPathListButtonsWidget); + + QStringList addedPaths = this->PathListWidget->addPaths(paths); + if (addedPaths != paths) + { + QString problematicPaths; + foreach(const QString& path, paths) + { + if (!addedPaths.contains(path)) + { + problematicPaths += path + '\n'; + } + } + QMessageBox::information(q, tr("Adding paths failed"), + QString(tr("Failed to add the following paths:\n\n%1\nPlease check your permissions.")) + .arg(problematicPaths)); + } +} + + +//----------------------------------------------------------------------------- +// ctkPathListButtonsWidget methods + +//----------------------------------------------------------------------------- +ctkPathListButtonsWidget::~ctkPathListButtonsWidget() +{ +} + +void ctkPathListButtonsWidget::init(ctkPathListWidget *pathListWidget) +{ + Q_D(ctkPathListButtonsWidget); + d->PathListWidget = pathListWidget; + + if (d->PathListWidget->selectionModel()->selectedIndexes().isEmpty()) + { + d->RemoveButton->setEnabled(false); + d->EditButton->setEnabled(false); + } + + switch(d->PathListWidget->mode()) + { + case ctkPathListWidget::FilesOnly: + d->AddDirectoryButton->setVisible(false); + break; + case ctkPathListWidget::DirectoriesOnly: + d->AddFilesButton->setVisible(false); + break; + default: + break; + } + + connect(d->PathListWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + d, SLOT(on_PathListWidget_selectionChanged(QItemSelection,QItemSelection))); + connect(d->PathListWidget, SIGNAL(pathActivated(QString)), d, SLOT(on_EditButton_clicked())); +} + +//----------------------------------------------------------------------------- +ctkPathListButtonsWidget::ctkPathListButtonsWidget(QWidget* newParent) + : Superclass(newParent) + , d_ptr(new ctkPathListButtonsWidgetPrivate(*this)) +{ + Q_D(ctkPathListButtonsWidget); + d->init(); +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidget::isAddFilesButtonVisible() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton->isVisible(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setAddFilesButtonVisible(bool visible) +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setVisible(visible); +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidget::isAddDirectoryButtonVisible() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddDirectoryButton->isVisible(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setAddDirectoryButtonVisible(bool visible) +{ + Q_D(ctkPathListButtonsWidget); + d->AddDirectoryButton->setVisible(visible); +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidget::isRemoveButtonVisible() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->RemoveButton->isVisible(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setRemoveButtonVisible(bool visible) +{ + Q_D(ctkPathListButtonsWidget); + d->RemoveButton->setVisible(visible); +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidget::isEditButtonVisible() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->EditButton->isVisible(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setEditButtonVisible(bool visible) +{ + Q_D(ctkPathListButtonsWidget); + d->EditButton->setVisible(visible); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::textAddFilesButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton->text(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::textAddDirectoryButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddDirectoryButton->text(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::textRemoveButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->RemoveButton->text(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::textEditButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->EditButton->text(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setTextAddFilesButton(const QString& text) +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setText(text); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setTextAddDirectoryButton(const QString& text) +{ + Q_D(ctkPathListButtonsWidget); + d->AddDirectoryButton->setText(text); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setTextRemoveButton(const QString& text) +{ + Q_D(ctkPathListButtonsWidget); + d->RemoveButton->setText(text); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setTextEditButton(const QString& text) +{ + Q_D(ctkPathListButtonsWidget); + d->EditButton->setText(text); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::toolTipAddFilesButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton->toolTip(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::toolTipAddDirectoryButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddDirectoryButton->toolTip(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::toolTipRemoveButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->RemoveButton->toolTip(); +} + +//----------------------------------------------------------------------------- +QString ctkPathListButtonsWidget::toolTipEditButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->EditButton->toolTip(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setToolTipAddFilesButton(const QString& toolTip) +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setToolTip(toolTip); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setToolTipAddDirectoryButton(const QString& toolTip) +{ + Q_D(ctkPathListButtonsWidget); + d->AddDirectoryButton->setToolTip(toolTip); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setToolTipRemoveButton(const QString& toolTip) +{ + Q_D(ctkPathListButtonsWidget); + d->RemoveButton->setToolTip(toolTip); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setToolTipEditButton(const QString& toolTip) +{ + Q_D(ctkPathListButtonsWidget); + d->EditButton->setToolTip(toolTip); +} + +//----------------------------------------------------------------------------- +QIcon ctkPathListButtonsWidget::iconAddFilesButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton->icon(); +} + +//----------------------------------------------------------------------------- +QIcon ctkPathListButtonsWidget::iconAddDirectoryButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddDirectoryButton->icon(); +} + +//----------------------------------------------------------------------------- +QIcon ctkPathListButtonsWidget::iconRemoveButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->RemoveButton->icon(); +} + +//----------------------------------------------------------------------------- +QIcon ctkPathListButtonsWidget::iconEditButton() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->EditButton->icon(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setIconAddFilesButton(const QIcon& icon) +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setIcon(icon); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setIconAddDirectoryButton(const QIcon& icon) +{ + Q_D(ctkPathListButtonsWidget); + d->AddDirectoryButton->setIcon(icon); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setIconRemoveButton(const QIcon& icon) +{ + Q_D(ctkPathListButtonsWidget); + d->RemoveButton->setIcon(icon); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setIconEditButton(const QIcon& icon) +{ + Q_D(ctkPathListButtonsWidget); + d->EditButton->setIcon(icon); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::unsetIconAddFilesButton() +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setIcon(QIcon(":/Icons/plus.png")); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::unsetIconAddDirectoryButton() +{ + Q_D(ctkPathListButtonsWidget); + d->AddDirectoryButton->setIcon(QIcon(":/Icons/plus.png")); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::unsetIconRemoveButton() +{ + Q_D(ctkPathListButtonsWidget); + d->RemoveButton->setIcon(QIcon(":/Icons/minus.png")); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::unsetIconEditButton() +{ + Q_D(ctkPathListButtonsWidget); + d->EditButton->setIcon(QIcon(":/Icons/edit.png")); +} + +//----------------------------------------------------------------------------- +bool ctkPathListButtonsWidget::isButtonsAutoRaise() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton->autoRaise(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setButtonsAutoRaise(bool autoRaise) +{ + Q_D(ctkPathListButtonsWidget); + d->AddFilesButton->setAutoRaise(autoRaise); + d->AddDirectoryButton->setAutoRaise(autoRaise); + d->RemoveButton->setAutoRaise(autoRaise); + d->EditButton->setAutoRaise(autoRaise); +} + +//----------------------------------------------------------------------------- +int ctkPathListButtonsWidget::buttonSpacing() const +{ + return this->layout()->spacing(); +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setButtonSpacing(int spacing) +{ + this->layout()->setSpacing(spacing); +} + +//----------------------------------------------------------------------------- +Qt::Orientation ctkPathListButtonsWidget::orientation() const +{ + return qobject_cast<QVBoxLayout*>(this->layout()) ? Qt::Vertical : Qt::Horizontal; +} + +//----------------------------------------------------------------------------- +void ctkPathListButtonsWidget::setOrientation(Qt::Orientation orientation) +{ + QVBoxLayout* verticalLayout = qobject_cast<QVBoxLayout*>(this->layout()); + if (verticalLayout && orientation == Qt::Vertical) + { + return; + } + + QLayout* oldLayout = this->layout(); + QLayout* newLayout = NULL; + if (orientation == Qt::Vertical) + { + newLayout = new QVBoxLayout; + } + else + { + newLayout = new QHBoxLayout; + } + newLayout->setContentsMargins(0,0,0,0); + newLayout->setSpacing(oldLayout->spacing()); + + QLayoutItem* item = 0; + while((item = oldLayout->takeAt(0))) + { + if (item->widget()) + { + newLayout->addWidget(item->widget()); + } + } + delete oldLayout; + this->setLayout(newLayout); +} + +//----------------------------------------------------------------------------- +QToolButton *ctkPathListButtonsWidget::buttonAddFiles() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddFilesButton; +} + +//----------------------------------------------------------------------------- +QToolButton *ctkPathListButtonsWidget::buttonAddDirectory() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->AddDirectoryButton; +} + +//----------------------------------------------------------------------------- +QToolButton *ctkPathListButtonsWidget::buttonEdit() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->EditButton; +} + +//----------------------------------------------------------------------------- +QToolButton *ctkPathListButtonsWidget::buttonRemove() const +{ + Q_D(const ctkPathListButtonsWidget); + return d->RemoveButton; +} diff --git a/Libs/Widgets/ctkPathListButtonsWidget.h b/Libs/Widgets/ctkPathListButtonsWidget.h new file mode 100644 index 0000000000..44ccdfb93c --- /dev/null +++ b/Libs/Widgets/ctkPathListButtonsWidget.h @@ -0,0 +1,157 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) University College London. + + 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 __ctkPathListButtonsWidget_h +#define __ctkPathListButtonsWidget_h + +// Qt includes +#include <QWidget> + + +// QtGUI includes +#include "ctkWidgetsExport.h" +#include "ctkPathListWidget.h" + +class ctkPathListButtonsWidgetPrivate; + +class QToolButton; + + +/// \ingroup Widgets +/// +/// \brief A widget with add, remove and edit buttons to be used together with ctkPathListWidget. +/// +/// This widget should be initialized with a ctkPathListWidget instance in order to work properly. +/// +/// \sa init(ctkPathListWidget*) +/// +/// \author m.clarkson@ucl.ac.uk +/// \author s.zelzer@dkfz-heidelberg.de +/// +class CTK_WIDGETS_EXPORT ctkPathListButtonsWidget : public QWidget +{ + Q_OBJECT + + Q_PROPERTY(bool showAddFilesButton READ isAddFilesButtonVisible WRITE setAddFilesButtonVisible) + Q_PROPERTY(bool showAddDirectoryButton READ isAddDirectoryButtonVisible WRITE setAddDirectoryButtonVisible) + Q_PROPERTY(bool showRemoveButton READ isRemoveButtonVisible WRITE setRemoveButtonVisible) + Q_PROPERTY(bool showEditButton READ isEditButtonVisible WRITE setEditButtonVisible) + + Q_PROPERTY(QString textAddFilesButton READ textAddFilesButton WRITE setTextAddFilesButton) + Q_PROPERTY(QString textAddDirectoryButton READ textAddDirectoryButton WRITE setTextAddDirectoryButton) + Q_PROPERTY(QString textRemoveButton READ textRemoveButton WRITE setTextRemoveButton) + Q_PROPERTY(QString textEditButton READ textEditButton WRITE setTextEditButton) + + Q_PROPERTY(QString toolTipAddFilesButton READ toolTipAddFilesButton WRITE setToolTipAddFilesButton) + Q_PROPERTY(QString toolTipAddDirectoryButton READ toolTipAddDirectoryButton WRITE setToolTipAddDirectoryButton) + Q_PROPERTY(QString toolTipRemoveButton READ toolTipRemoveButton WRITE setToolTipRemoveButton) + Q_PROPERTY(QString toolTipEditButton READ toolTipEditButton WRITE setToolTipEditButton) + + Q_PROPERTY(QIcon iconAddFilesButton READ iconAddFilesButton WRITE setIconAddFilesButton RESET unsetIconAddFilesButton) + Q_PROPERTY(QIcon iconAddDirectoryButton READ iconAddDirectoryButton WRITE setIconAddDirectoryButton RESET unsetIconAddDirectoryButton) + Q_PROPERTY(QIcon iconRemoveButton READ iconRemoveButton WRITE setIconRemoveButton RESET unsetIconRemoveButton) + Q_PROPERTY(QIcon iconEditButton READ iconEditButton WRITE setIconEditButton RESET unsetIconEditButton) + + Q_PROPERTY(bool buttonsAutoRaise READ isButtonsAutoRaise WRITE setButtonsAutoRaise) + Q_PROPERTY(int buttonSpacing READ buttonSpacing WRITE setButtonSpacing) + + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) + +public: + + /// Superclass typedef + typedef QWidget Superclass; + + ctkPathListButtonsWidget(QWidget* parent = 0); + virtual ~ctkPathListButtonsWidget(); + + /// Initialize this widget with a ctkPathListWidget. + void init(ctkPathListWidget* pathListWidget); + + bool isAddFilesButtonVisible() const; + void setAddFilesButtonVisible(bool visible); + + bool isAddDirectoryButtonVisible() const; + void setAddDirectoryButtonVisible(bool visible); + + bool isRemoveButtonVisible() const; + void setRemoveButtonVisible(bool visible); + + bool isEditButtonVisible() const; + void setEditButtonVisible(bool visible); + + QString textAddFilesButton() const; + QString textAddDirectoryButton() const; + QString textRemoveButton() const; + QString textEditButton() const; + + void setTextAddFilesButton(const QString& text); + void setTextAddDirectoryButton(const QString& text); + void setTextRemoveButton(const QString& text); + void setTextEditButton(const QString& text); + + QString toolTipAddFilesButton() const; + QString toolTipAddDirectoryButton() const; + QString toolTipRemoveButton() const; + QString toolTipEditButton() const; + + void setToolTipAddFilesButton(const QString& toolTip); + void setToolTipAddDirectoryButton(const QString& toolTip); + void setToolTipRemoveButton(const QString& toolTip); + void setToolTipEditButton(const QString& toolTip); + + QIcon iconAddFilesButton() const; + QIcon iconAddDirectoryButton() const; + QIcon iconRemoveButton() const; + QIcon iconEditButton() const; + + void setIconAddFilesButton(const QIcon& icon); + void setIconAddDirectoryButton(const QIcon& icon); + void setIconRemoveButton(const QIcon& icon); + void setIconEditButton(const QIcon& icon); + + void unsetIconAddFilesButton(); + void unsetIconAddDirectoryButton(); + void unsetIconRemoveButton(); + void unsetIconEditButton(); + + bool isButtonsAutoRaise() const; + void setButtonsAutoRaise(bool autoRaise); + + int buttonSpacing() const; + void setButtonSpacing(int spacing); + + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + + QToolButton* buttonAddFiles() const; + QToolButton* buttonAddDirectory() const; + QToolButton* buttonEdit() const; + QToolButton* buttonRemove() const; + +protected: + QScopedPointer<ctkPathListButtonsWidgetPrivate> d_ptr; + +private: + Q_DECLARE_PRIVATE(ctkPathListButtonsWidget) + Q_DISABLE_COPY(ctkPathListButtonsWidget) +}; + +#endif diff --git a/Libs/Widgets/ctkDirectoryListWidget_p.h b/Libs/Widgets/ctkPathListButtonsWidget_p.h similarity index 51% rename from Libs/Widgets/ctkDirectoryListWidget_p.h rename to Libs/Widgets/ctkPathListButtonsWidget_p.h index 09a54188cf..ccb69f38d5 100644 --- a/Libs/Widgets/ctkDirectoryListWidget_p.h +++ b/Libs/Widgets/ctkPathListButtonsWidget_p.h @@ -18,43 +18,57 @@ =========================================================================*/ -#ifndef __ctkDirectoryListWidget_p_h -#define __ctkDirectoryListWidget_p_h +#ifndef __ctkPathListButtonsWidget_p_h +#define __ctkPathListButtonsWidget_p_h // Qt includes #include <QObject> -#include <QStringList> // CTK includes -#include "ctkDirectoryListWidget.h" -#include "ui_ctkDirectoryListWidget.h" +#include "ui_ctkPathListButtonsWidget.h" -//----------------------------------------------------------------------------- -/// \ingroup Widgets +class ctkPathListButtonsWidget; +class ctkPathListWidget; + +class QFileDialog; -class ctkDirectoryListWidgetPrivate : public QObject, public Ui_ctkDirectoryListWidget +//----------------------------------------------------------------------------- +class ctkPathListButtonsWidgetPrivate : public QObject, public Ui_ctkPathListButtonsWidget { Q_OBJECT - Q_DECLARE_PUBLIC(ctkDirectoryListWidget); + Q_DECLARE_PUBLIC(ctkPathListButtonsWidget) + protected: - ctkDirectoryListWidget* const q_ptr; + + ctkPathListButtonsWidget* const q_ptr; + public: - explicit ctkDirectoryListWidgetPrivate(ctkDirectoryListWidget& object); - virtual ~ctkDirectoryListWidgetPrivate(); + + explicit ctkPathListButtonsWidgetPrivate(ctkPathListButtonsWidget& object); + virtual ~ctkPathListButtonsWidgetPrivate(); void init(); void setupUi(QWidget * parent); - void setDirectoryList(const QStringList& list); - QStringList directoryList() const; - public Q_SLOTS: - void onAddClicked(); - void onRemoveClicked(); - void onExpandClicked(bool); - void onDirectoryListChanged(); + + void on_AddFilesButton_clicked(); + void on_AddDirButton_clicked(); + void on_RemoveButton_clicked(); + void on_EditButton_clicked(); + + void on_PathListWidget_selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); public: + + ctkPathListWidget* PathListWidget; + +private: + + QStringList openAddFilesDialog(bool multiple = true); + QStringList openAddDirDialog(); + + void addPathsWithWarningMessage(const QStringList& paths); }; #endif diff --git a/Libs/Widgets/ctkPathListWidget.cpp b/Libs/Widgets/ctkPathListWidget.cpp new file mode 100644 index 0000000000..f8a070dc94 --- /dev/null +++ b/Libs/Widgets/ctkPathListWidget.cpp @@ -0,0 +1,813 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +=========================================================================*/ + +// Qt includes +#include <QFileInfo> +#include <QHBoxLayout> +#include <QListView> +#include <QStandardItemModel> +#include <QApplication> + +// QtGUI includes +#include "ctkPathListWidget.h" + +// -------------------------------------------------------------------------- +// ctkPathListWidgetPrivate + +//----------------------------------------------------------------------------- +class ctkPathListWidgetPrivate +{ + Q_DECLARE_PUBLIC(ctkPathListWidget) + +protected: + ctkPathListWidget* const q_ptr; + +public: + + enum PathType { + Unknown, + File, + Directory + }; + + ctkPathListWidgetPrivate(ctkPathListWidget& object); + + void _q_emitPathClicked(const QModelIndex &index); + void _q_emitPathDoubleClicked(const QModelIndex &index); + void _q_emitPathActivated(const QModelIndex &index); + void _q_emitCurrentPathChanged(const QModelIndex ¤t, const QModelIndex &previous); + + bool addPath(const QString& path); + bool removePath(const QString& path); + + void fileOptionsChanged(); + void directoryOptionsChanged(); + + PathType pathType(const QString& absolutePath) const; + + bool isValidPath(const QString& absoluteFilePath, PathType pathType) const; + bool isValidFile(const QString& absoluteFilePath) const; + bool isValidDir(const QString& absoluteDirPath) const; + + QStandardItemModel PathListModel; + ctkPathListWidget::Mode Mode; + ctkPathListWidget::PathOptions FileOptions; + ctkPathListWidget::PathOptions DirectoryOptions; + QIcon FileIcon; + QIcon DirectoryIcon; +}; + +// -------------------------------------------------------------------------- +// ctkPathListWidgetPrivate methods + +#include "moc_ctkPathListWidget.h" + +// -------------------------------------------------------------------------- +ctkPathListWidgetPrivate::ctkPathListWidgetPrivate(ctkPathListWidget& object) + : q_ptr(&object) + , Mode(ctkPathListWidget::Any) + , FileOptions(ctkPathListWidget::Exists | ctkPathListWidget::Readable) + , DirectoryOptions(ctkPathListWidget::Exists | ctkPathListWidget::Readable) +{ +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::_q_emitPathClicked(const QModelIndex &index) +{ + Q_Q(ctkPathListWidget); + emit q->pathClicked(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString()); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::_q_emitPathDoubleClicked(const QModelIndex &index) +{ + Q_Q(ctkPathListWidget); + emit q->pathDoubleClicked(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString()); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::_q_emitPathActivated(const QModelIndex &index) +{ + Q_Q(ctkPathListWidget); + emit q->pathActivated(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString()); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::_q_emitCurrentPathChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_Q(ctkPathListWidget); + QString currentPath = this->PathListModel.data(current, ctkPathListWidget::AbsolutePathRole).toString(); + QString previousPath = this->PathListModel.data(previous, ctkPathListWidget::AbsolutePathRole).toString(); + emit q->currentPathChanged(currentPath, previousPath); +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidgetPrivate::addPath(const QString& path) +{ + Q_Q(ctkPathListWidget); + QString absolutePath = QFileInfo(path).absoluteFilePath(); + if (q->contains(absolutePath)) + { + return false; + } + + PathType pathType = this->pathType(absolutePath); + if (!this->isValidPath(absolutePath, pathType)) + { + return false; + } + QStandardItem * item = new QStandardItem(path); + item->setData(QVariant(absolutePath), Qt::ToolTipRole); + item->setData(QVariant(absolutePath), ctkPathListWidget::AbsolutePathRole); + if (pathType == File && !this->FileIcon.isNull()) + { + item->setData(this->FileIcon, Qt::DecorationRole); + } + else if (pathType == Directory && !this->DirectoryIcon.isNull()) + { + item->setData(this->DirectoryIcon, Qt::DecorationRole); + } + this->PathListModel.appendRow(item); + return true; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidgetPrivate::removePath(const QString& path) +{ + QString absolutePath = QFileInfo(path).absoluteFilePath(); + QModelIndexList foundIndices = this->PathListModel.match(this->PathListModel.index(0, 0), + ctkPathListWidget::AbsolutePathRole, + absolutePath); + Q_ASSERT(foundIndices.count() < 2); + if (!foundIndices.isEmpty()) + { + this->PathListModel.removeRow(foundIndices.front().row()); + return true; + } + return false; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::fileOptionsChanged() +{ + QStringList removedPaths; + for(int i = 0; i < this->PathListModel.rowCount();) + { + QModelIndex index = this->PathListModel.index(i, 0); + QString filePath = this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString(); + if (!this->isValidFile(filePath)) + { + this->PathListModel.removeRow(i); + removedPaths << filePath; + } + else + { + ++i; + } + } + + if (!removedPaths.empty()) + { + Q_Q(ctkPathListWidget); + emit q->pathsChanged(QStringList(), removedPaths); + } +} + +// -------------------------------------------------------------------------- +void ctkPathListWidgetPrivate::directoryOptionsChanged() +{ + QStringList removedPaths; + for(int i = 0; i < this->PathListModel.rowCount();) + { + QModelIndex index = this->PathListModel.index(i, 0); + QString dirPath = this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString(); + if (!this->isValidDir(dirPath)) + { + this->PathListModel.removeRow(i); + removedPaths << dirPath; + } + else + { + ++i; + } + } + + if (!removedPaths.empty()) + { + Q_Q(ctkPathListWidget); + emit q->pathsChanged(QStringList(), removedPaths); + } +} + +// -------------------------------------------------------------------------- +ctkPathListWidgetPrivate::PathType ctkPathListWidgetPrivate::pathType(const QString& absolutePath) const +{ + QFileInfo fileInfo(absolutePath); + if (fileInfo.exists()) + { + if (fileInfo.isFile()) + { + return File; + } + else if (fileInfo.isDir()) + { + return Directory; + } + return Unknown; + } + // Check if path is a file or directory by looking for a trailing slash + else if (absolutePath.endsWith('/')) + { + return Directory; + } + else + { + return File; + } +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidgetPrivate::isValidPath(const QString& absoluteFilePath, PathType pathType) const +{ + switch (pathType) + { + case Unknown: + if (this->Mode == ctkPathListWidget::Any) + { + return true; + } + return false; + case File: + return this->isValidFile(absoluteFilePath); + case Directory: + return this->isValidDir(absoluteFilePath); + default: + return false; + } +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidgetPrivate::isValidFile(const QString& absoluteFilePath) const +{ + if (this->Mode == ctkPathListWidget::DirectoriesOnly) + { + return false; + } + + if (this->FileOptions.testFlag(ctkPathListWidget::None)) + { + return true; + } + else + { + QFileInfo fileInfo(absoluteFilePath); + if (fileInfo.exists()) + { + if (!fileInfo.isFile()) + { + return false; + } + if (this->FileOptions.testFlag(ctkPathListWidget::Readable) && + !fileInfo.isReadable()) + { + return false; + } + if (this->FileOptions.testFlag(ctkPathListWidget::Writable) && + !fileInfo.isWritable()) + { + return false; + } + if (this->FileOptions.testFlag(ctkPathListWidget::Executable) && + !fileInfo.isExecutable()) + { + return false; + } + return true; + } + else + { + return !this->FileOptions.testFlag(ctkPathListWidget::Exists); + } + } +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidgetPrivate::isValidDir(const QString& absoluteDirPath) const +{ + if (this->Mode == ctkPathListWidget::FilesOnly) + { + return false; + } + + if (this->DirectoryOptions.testFlag(ctkPathListWidget::None)) + { + return true; + } + else + { + QFileInfo fileInfo(absoluteDirPath); + if (fileInfo.exists()) + { + if (!fileInfo.isDir()) + { + return false; + } + if (this->DirectoryOptions.testFlag(ctkPathListWidget::Readable) && + !fileInfo.isReadable()) + { + return false; + } + if (this->DirectoryOptions.testFlag(ctkPathListWidget::Writable) && + !fileInfo.isWritable()) + { + return false; + } + if (this->DirectoryOptions.testFlag(ctkPathListWidget::Executable) && + !fileInfo.isExecutable()) + { + return false; + } + return true; + } + else + { + return !this->FileOptions.testFlag(ctkPathListWidget::Exists); + } + } +} + +// -------------------------------------------------------------------------- +// ctkPathListWidget methods + +// -------------------------------------------------------------------------- +ctkPathListWidget::ctkPathListWidget(QWidget* _parent) + : Superclass(_parent) + , d_ptr(new ctkPathListWidgetPrivate(*this)) +{ + Q_D(ctkPathListWidget); + + this->setSelectionBehavior(QAbstractItemView::SelectRows); + this->setSelectionMode(QAbstractItemView::ExtendedSelection); + this->setEditTriggers(QAbstractItemView::NoEditTriggers); + + this->unsetFileIcon(); + this->unsetDirectoryIcon(); + + QListView::setModel(&d->PathListModel); + + // signals + this->connect(this, SIGNAL(clicked(QModelIndex)), SLOT(_q_emitPathClicked(QModelIndex))); + this->connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(_q_emitPathDoubleClicked(QModelIndex))); + this->connect(this, SIGNAL(activated(QModelIndex)), SLOT(_q_emitPathActivated(QModelIndex))); + this->connect(this->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + SLOT(_q_emitCurrentPathChanged(QModelIndex,QModelIndex))); +} + +// -------------------------------------------------------------------------- +ctkPathListWidget::~ctkPathListWidget() +{ +} + +// -------------------------------------------------------------------------- +ctkPathListWidget::Mode ctkPathListWidget::mode() const +{ + Q_D(const ctkPathListWidget); + return d->Mode; +} + +// -------------------------------------------------------------------------- +QIcon ctkPathListWidget::fileIcon() const +{ + Q_D(const ctkPathListWidget); + return d->FileIcon; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setFileIcon(const QIcon& icon) +{ + Q_D(ctkPathListWidget); + d->FileIcon = icon; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::unsetFileIcon() +{ + Q_D(ctkPathListWidget); + d->FileIcon = QApplication::style()->standardIcon(QStyle::SP_FileIcon); +} + +// -------------------------------------------------------------------------- +QIcon ctkPathListWidget::directoryIcon() const +{ + Q_D(const ctkPathListWidget); + return d->DirectoryIcon; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setDirectoryIcon(const QIcon& icon) +{ + Q_D(ctkPathListWidget); + d->DirectoryIcon = icon; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::unsetDirectoryIcon() +{ + Q_D(ctkPathListWidget); + d->DirectoryIcon = QApplication::style()->standardIcon(QStyle::SP_DirIcon); +} + +// -------------------------------------------------------------------------- +ctkPathListWidget::PathOptions ctkPathListWidget::fileOptions() const +{ + Q_D(const ctkPathListWidget); + return d->FileOptions; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setFileOptions(PathOptions fileOptions) +{ + Q_D(ctkPathListWidget); + if (d->FileOptions != fileOptions) + { + d->FileOptions = fileOptions; + d->fileOptionsChanged(); + } +} + +// -------------------------------------------------------------------------- +ctkPathListWidget::PathOptions ctkPathListWidget::directoryOptions() const +{ + Q_D(const ctkPathListWidget); + return d->DirectoryOptions; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setDirectoryOptions(PathOptions directoryOptions) +{ + Q_D(ctkPathListWidget); + if (d->DirectoryOptions != directoryOptions) + { + d->DirectoryOptions = directoryOptions; + d->directoryOptionsChanged(); + } +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::files(bool absolutePath) const +{ + Q_D(const ctkPathListWidget); + QStringList fileList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkPathListWidget::AbsolutePathRole; + } + for(int i = 0; i < d->PathListModel.rowCount(); ++i) + { + QString filePath = d->PathListModel.data(d->PathListModel.index(i, 0), role).toString(); + if (d->pathType(filePath) == ctkPathListWidgetPrivate::File) + { + fileList << filePath; + } + } + return fileList; +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::directories(bool absolutePath) const +{ + Q_D(const ctkPathListWidget); + QStringList pathList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkPathListWidget::AbsolutePathRole; + } + for(int i = 0; i < d->PathListModel.rowCount(); ++i) + { + QString dirPath = d->PathListModel.data(d->PathListModel.index(i, 0), role).toString(); + if (d->pathType(dirPath) == ctkPathListWidgetPrivate::Directory) + { + pathList << dirPath; + } + } + return pathList; +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::paths(bool absolutePath)const +{ + Q_D(const ctkPathListWidget); + QStringList pathList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkPathListWidget::AbsolutePathRole; + } + for(int i = 0; i < d->PathListModel.rowCount(); ++i) + { + pathList << d->PathListModel.data(d->PathListModel.index(i, 0), role).toString(); + } + return pathList; +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::selectedPaths(bool absolutePath)const +{ + Q_D(const ctkPathListWidget); + QStringList pathList; + int role = Qt::DisplayRole; + if (absolutePath) + { + role = ctkPathListWidget::AbsolutePathRole; + } + QModelIndexList selectedIndexes = this->selectionModel()->selectedRows(); + foreach(const QModelIndex& index, selectedIndexes) + { + pathList << d->PathListModel.data(index, role).toString(); + } + return pathList; +} + +// -------------------------------------------------------------------------- +QString ctkPathListWidget::currentPath(bool absolutePath) const +{ + Q_D(const ctkPathListWidget); + + QModelIndex currentIndex = this->currentIndex(); + if (!currentIndex.isValid()) + { + return QString(); + } + + int role = absolutePath ? static_cast<int>(AbsolutePathRole) + : static_cast<int>(Qt::DisplayRole); + return d->PathListModel.data(currentIndex, role).toString(); +} + +// -------------------------------------------------------------------------- +int ctkPathListWidget::count() const +{ + return this->model()->rowCount(); +} + +// -------------------------------------------------------------------------- +QString ctkPathListWidget::path(int row) const +{ + Q_D(const ctkPathListWidget); + if (row < 0 || row >= count()) + { + return QString(); + } + return d->PathListModel.data(d->PathListModel.index(row, 0), AbsolutePathRole).toString(); +} + +// -------------------------------------------------------------------------- +QString ctkPathListWidget::pathAt(const QPoint& point) const +{ + Q_D(const ctkPathListWidget); + return d->PathListModel.data(indexAt(point), AbsolutePathRole).toString(); +} + +// -------------------------------------------------------------------------- +int ctkPathListWidget::row(const QString& path) const +{ + Q_D(const ctkPathListWidget); + QModelIndexList result = d->PathListModel.match(d->PathListModel.index(0,0), AbsolutePathRole, + QFileInfo(path).absoluteFilePath(), 1, Qt::MatchExactly); + Q_ASSERT(result.count() < 2); + if (!result.isEmpty()) + { + return result.front().row(); + } + return -1; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::editPath(const QString &oldPath, const QString &newPath) +{ + Q_D(ctkPathListWidget); + + QString oldAbsolutePath = QFileInfo(oldPath).absoluteFilePath(); + QModelIndexList matched = d->PathListModel.match(d->PathListModel.index(0,0), AbsolutePathRole, + oldAbsolutePath, 1, Qt::MatchExactly); + Q_ASSERT(matched.size() < 2); + if (matched.isEmpty()) + { + return false; + } + return this->editPath(matched.front(), newPath); +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::editPath(const QModelIndex &index, const QString &newPath) +{ + Q_D(ctkPathListWidget); + + if (!index.isValid()) + { + return false; + } + + QString oldAbsolutePath = d->PathListModel.data(index, AbsolutePathRole).toString(); + ctkPathListWidgetPrivate::PathType oldPathType = d->pathType(oldAbsolutePath); + ctkPathListWidgetPrivate::PathType newPathType = d->pathType(newPath); + if (oldPathType != newPathType) + { + return false; + } + + if (!d->isValidPath(newPath, newPathType)) + { + return false; + } + + QString newAbsolutePath = QFileInfo(newPath).absoluteFilePath(); + d->PathListModel.setData(index, newPath, Qt::DisplayRole); + d->PathListModel.setData(index, newAbsolutePath, AbsolutePathRole); + + emit this->pathsChanged(QStringList(newAbsolutePath), QStringList(oldAbsolutePath)); + return true; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::isFile(const QString &path) const +{ + Q_D(const ctkPathListWidget); + return d->pathType(path) == ctkPathListWidgetPrivate::File; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::isDirectory(const QString &path) const +{ + Q_D(const ctkPathListWidget); + return d->pathType(path) == ctkPathListWidgetPrivate::Directory; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setMode(ctkPathListWidget::Mode mode) +{ + Q_D(ctkPathListWidget); + d->Mode = mode; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::contains(const QString& path)const +{ + Q_D(const ctkPathListWidget); + QString absolutePath = QFileInfo(path).absoluteFilePath(); + QModelIndexList foundIndexes = d->PathListModel.match( + d->PathListModel.index(0, 0), ctkPathListWidget::AbsolutePathRole, + QVariant(absolutePath), 1, Qt::MatchExactly); + Q_ASSERT(foundIndexes.size() < 2); + return (foundIndexes.size() != 0); +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::addPath(const QString& path) +{ + return !this->addPaths(QStringList() << path).empty(); +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::addPaths(const QStringList &paths) +{ + Q_D(ctkPathListWidget); + + QStringList addedPaths; + foreach(const QString& path, paths) + { + if (d->addPath(path)) + { + addedPaths << QFileInfo(path).absoluteFilePath(); + } + } + + if (!addedPaths.empty()) + { + emit this->pathsChanged(addedPaths, QStringList()); + } + return addedPaths; +} + +// -------------------------------------------------------------------------- +bool ctkPathListWidget::removePath(const QString& path) +{ + return !this->removePaths(QStringList() << path).empty(); +} + +// -------------------------------------------------------------------------- +QStringList ctkPathListWidget::removePaths(const QStringList &paths) +{ + Q_D(ctkPathListWidget); + + QStringList removedPaths; + foreach(const QString& path, paths) + { + if (d->removePath(path)) + { + removedPaths << QFileInfo(path).absoluteFilePath(); + } + } + + if (!removedPaths.empty()) + { + emit this->pathsChanged(QStringList(), removedPaths); + } + return removedPaths; +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::removeSelectedPaths() +{ + Q_D(ctkPathListWidget); + + QModelIndexList selectedIndexes = this->selectionModel()->selectedRows(); + if (selectedIndexes.empty()) return; + + QStringList removedPaths; + while(selectedIndexes.count() > 0) + { + removedPaths << d->PathListModel.data(selectedIndexes.front(), AbsolutePathRole).toString(); + d->PathListModel.removeRow(selectedIndexes.front().row()); + selectedIndexes = this->selectionModel()->selectedRows(); + } + + emit this->pathsChanged(QStringList(), removedPaths); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::clear() +{ + Q_D(ctkPathListWidget); + if (d->PathListModel.rowCount() == 0) return; + + QStringList removedPaths = this->paths(true); + d->PathListModel.clear(); + emit this->pathsChanged(QStringList(), removedPaths); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setPaths(const QStringList& paths) +{ + Q_D(ctkPathListWidget); + + QStringList addedPaths; + QStringList removedPaths; + + QStringList absolutePaths; + foreach(const QString& path, paths) + { + absolutePaths << QFileInfo(path).absoluteFilePath(); + } + + foreach(const QString& path, this->paths(true)) + { + if (!absolutePaths.contains(path) && d->removePath(path)) + { + removedPaths << path; + } + } + + for(int i = 0; i < paths.count(); ++i) + { + if (!this->contains(paths[i]) && d->addPath(paths[i])) + { + addedPaths << absolutePaths[i]; + } + } + + if (addedPaths.isEmpty() && removedPaths.empty()) + { + return; + } + + emit this->pathsChanged(addedPaths, removedPaths); +} + +// -------------------------------------------------------------------------- +void ctkPathListWidget::setModel(QAbstractItemModel*) +{ + Q_ASSERT(!"ctkPathListWidget::setModel() - Changing the model of the ctkPathListWidget is not allowed."); +} diff --git a/Libs/Widgets/ctkPathListWidget.h b/Libs/Widgets/ctkPathListWidget.h new file mode 100644 index 0000000000..28dc7eabd7 --- /dev/null +++ b/Libs/Widgets/ctkPathListWidget.h @@ -0,0 +1,307 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) Kitware Inc. + + 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. + + This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc. + and was partially funded by NIH grant 3P41RR013218-12S1 + +=========================================================================*/ + +#ifndef __ctkPathListWidget_h +#define __ctkPathListWidget_h + +// Qt includes +#include <QListView> + +// QtGUI includes +#include "ctkWidgetsExport.h" + +class ctkPathListWidgetPrivate; + +/// \ingroup Widgets +/// +/// \brief The ctkPathListWidget lists files and/or directories. +/// +/// The ctkPathListWidget is a QListView sub-class tailored specifically for displaying +/// lists of file and/or directory entries. A \e path denotes either a file or a directory. +/// Paths can be relative or absolute and the range of valid paths can be constrained +/// by setting file and directory options. +/// +class CTK_WIDGETS_EXPORT ctkPathListWidget : public QListView +{ + Q_OBJECT + + /// The current list of paths. + Q_PROPERTY(QStringList paths READ paths WRITE setPaths NOTIFY pathsChanged) + + /// The mode for this ctkPathListWidget. + Q_PROPERTY(Mode mode READ mode WRITE setMode) + + /// Constraints on the file type. + Q_PROPERTY(PathOptions fileOptions READ fileOptions WRITE setFileOptions) + + /// Constraints on the directory type. + Q_PROPERTY(PathOptions directoryOptions READ directoryOptions WRITE setDirectoryOptions) + + /// The icon to be shown for a file entry. + Q_PROPERTY(QIcon fileIcon READ fileIcon WRITE setFileIcon RESET unsetFileIcon) + + /// The icon to be shown for a directory entry. + Q_PROPERTY(QIcon directoryIcon READ directoryIcon WRITE setDirectoryIcon RESET unsetDirectoryIcon) + + Q_FLAGS(PathOption PathOptions) + Q_ENUMS(Mode) + +public: + + enum + { + /// A role for getting the absolute path from items in this list views model. + AbsolutePathRole = Qt::UserRole + 1 + }; + + /// Describes constraints on paths. + enum PathOption + { + /// No constraints + None = 0x00, + /// The path must exist in the file system. + Exists = 0x01, + /// The path must be readable by the current user. + Readable = 0x02, + /// The path must be writable by the current user. + Writable = 0x04, + /// The path must be executable by the current user. + Executable = 0x08 + }; + Q_DECLARE_FLAGS(PathOptions, PathOption) + + enum Mode + { + /// Allow all paths. + Any = 0, + /// Allow only file entries. + FilesOnly, + /// Allow only directory entries. + DirectoriesOnly + }; + + /// Superclass typedef + typedef QListView Superclass; + + /// Constructor + explicit ctkPathListWidget(QWidget* parent = 0); + + /// Destructor + virtual ~ctkPathListWidget(); + + /// \return The current widget mode. + Mode mode() const; + + /// \return The QIcon used for file entries. + QIcon fileIcon() const; + + /// Sets a QIcon to be used for file entries. + /// \param icon The new file entry icon. + void setFileIcon(const QIcon& icon); + + /// Un-set any custom file icon. + void unsetFileIcon(); + + /// \return The QIcon used for directory entries. + QIcon directoryIcon() const; + + /// Sets a QIcon to be used for directory entries. + /// \param icon The new directory entry icon. + void setDirectoryIcon(const QIcon& icon); + + /// Un-set any custom directory icon. + void unsetDirectoryIcon(); + + /// \return The file entry constraints. + PathOptions fileOptions() const; + + /// Set new file entry constraints. + /// \param fileOptions The file entry constraints. + void setFileOptions(PathOptions fileOptions); + + /// \return The directory entry constraints. + PathOptions directoryOptions() const; + + /// Set new directory entry constraints. + /// \param directoryOptions The directory entry constraints. + void setDirectoryOptions(PathOptions directoryOptions); + + /// Checks if an entry with the given \a path already exists. + /// \return <code>true</code> if the \a path has already been added, <code>false</code> otherwise. + bool contains(const QString& path)const; + + /// Get all file entries. + /// \param absolutePath If <code>true</code>, resolve all entries to absolute paths. + /// \return A list of all file entries. + QStringList files(bool absolutePath = false) const; + + /// Get all directory entries. + /// \param absolutePath If <code>true</code>, resolve all entries to absolute paths. + /// \return A list of all directory entries. + QStringList directories(bool absolutePath = false) const; + + /// Get all path entries. + /// \param absolutePath If <code>true</code>, resolve all entries to absolute paths. + /// \return A list of all entries. + QStringList paths(bool absolutePath = false) const; + + /// Get all selected path entries. + /// \param absolutePath If <code>true</code>, resolve all entries to absolute paths. + /// \return A list of all selected entries. + QStringList selectedPaths(bool absolutePath = false) const; + + /// Get the currently focused path entry. + /// \param absolutePath If <code>true</code>, resolve all entries to absolute paths. + /// \return The focused path entry or a null QString if no entry is focused. + QString currentPath(bool absolutePath = false) const; + + /// \return The current entry count. + int count() const; + + /// \return The absolute path for \a row or a null QString if \a row is out of range. + QString path(int row) const; + + /// \return The absolute path for the entry located at the point \a point (in the + /// widget coordinate system) or a null QString if no entry could be found for \a point. + QString pathAt(const QPoint& point) const; + + /// \see pathAt(const QPoint&) + QString pathAt(int x, int y) const { return pathAt(QPoint(x, y)); } + + /// \return The row number for the given \a path or -1 if \a path is not in the list of current + /// entries. + int row(const QString& path) const; + + /// Changes \a oldPath to the new value given by \a newPath. Does nothing if \a oldPath is not + /// in the list or \a newPath does not fullfill the current path options (constraints). + /// \param oldPath The path to be edited. + /// \param newPath The new path replacing \a oldPath. + /// \return <code>true</code> if the old path was successfully changed, <code>false</code> otherwise. + bool editPath(const QString& oldPath, const QString& newPath); + + /// Changes the path value of \a index to \a newPath. + /// \param index The model index for which the path will be changed. + /// \param newPath The new path replacing the path value of \a index. + /// + /// \sa editPath(const QString&, const QString&) + bool editPath(const QModelIndex& index, const QString& newPath); + + /// \return Returns <code>true</code> if the given path is treated as a file, + /// <code>false</code> otherwise. + bool isFile(const QString& path) const; + + /// \return Returns <code>true</code> if the given path is treated as a directory, + /// <code>false</code> otherwise. + bool isDirectory(const QString& path) const; + +public Q_SLOTS: + + /// Set the mode for controlling the path type. + /// \param mode The path mode. + void setMode(Mode mode); + + /// Depending on the mode and path constraints, add \a path to the entry list and emit signal pathListChanged(). + /// \param path The path to add. + /// \return <code>true</code> if the path was added, <code>false</code> otherwise. + /// + /// \sa pathListChanged() + bool addPath(const QString& path); + + /// Depending on the mode and path constraints, add \a paths to the entry list and emit signal pathListChanged(). + /// \param paths The paths to add. + /// \return The absolute paths of all added entries from \a paths. + /// + /// \sa pathListChanged() + QStringList addPaths(const QStringList& paths); + + /// Remove all entries and set all valid entries in \a paths as the current list. + /// The signal pathListChanged() is emitted if the old list of paths is + /// different from the provided one. + /// \param paths The new path list. + /// + /// \sa addPaths(), pathListChanged() + void setPaths(const QStringList& paths); + + /// Remove \a path from the list. + /// The signal pathListChanged() is emitted if the path was in the list. + /// \param path The path to remove. + /// \return <code>true</code> if \a path was removed, <code>false</code> otherwise. + /// + /// \sa pathListChanged() + bool removePath(const QString& path); + + /// Remove \a paths from the list. + /// \param paths The paths to remove. + /// \return The absolute paths of all removed entries from \a paths. + QStringList removePaths(const QStringList& paths); + + /// Remove all currently selected paths from the list. + void removeSelectedPaths(); + + /// Remove all paths from the list. + void clear(); + +Q_SIGNALS: + + /// This signal is emitted when paths are added or removed to the list. + /// \param added The newly added absolute paths. + /// \param removed The removed absolute paths. + void pathsChanged(const QStringList& added, const QStringList& removed); + + /// The user clicked on a path entry. + void pathClicked(const QString& absolutePath); + + /// The user double-clicked on a path entry. + void pathDoubleClicked(const QString& absolutePath); + + /// This signal is emitted when the \a absolutePath entry is activated. The entry is activated when the user + /// clicks or double clicks on it, depending on the system configuration. It is also activated + /// when the user presses the activation key (on Windows and X11 this is the Return key, on + /// Mac OS X it is Ctrl+0). + void pathActivated(const QString& absolutePath); + + /// This signal is emitted whenever the current item changes. + /// \param currentAbsolutePath The new current path entry. + /// \param previousAbsolutePath The path entry that previously had the focus. + void currentPathChanged(const QString& currentAbsolutePath, const QString& previousAbsolutePath); + +protected: + QScopedPointer<ctkPathListWidgetPrivate> d_ptr; + +private: + + void setModel(QAbstractItemModel *model); + + Q_DECLARE_PRIVATE(ctkPathListWidget) + Q_DISABLE_COPY(ctkPathListWidget) + + Q_PRIVATE_SLOT(d_func(), void _q_emitPathClicked(const QModelIndex& index)) + Q_PRIVATE_SLOT(d_func(), void _q_emitPathDoubleClicked(const QModelIndex& index)) + Q_PRIVATE_SLOT(d_func(), void _q_emitPathActivated(const QModelIndex& index)) + Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentPathChanged(const QModelIndex &previous, const QModelIndex ¤t)) +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(ctkPathListWidget::PathOptions) + +#endif + From fd907351aa702e71024951d4fb282cc7c0b15e27 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:09:59 +0200 Subject: [PATCH 139/247] Factored out helper classes for QtConcurrent mapped functions. --- Libs/CommandLineModules/Core/CMakeLists.txt | 1 + .../ctkCmdLineModuleConcurrentHelpers.cpp | 93 +++++++++++++++++++ .../Core/ctkCmdLineModuleConcurrentHelpers.h | 77 +++++++++++++++ .../Core/ctkCmdLineModuleDirectoryWatcher.cpp | 72 +------------- 4 files changed, 175 insertions(+), 68 deletions(-) create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index e9327a0e40..fe17456b99 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -17,6 +17,7 @@ set(KIT_SRCS ctkCmdLineModuleBackend.cpp ctkCmdLineModuleCache.cpp ctkCmdLineModuleCache_p.h + ctkCmdLineModuleConcurrentHelpers.cpp ctkCmdLineModuleDefaultPathBuilder.cpp ctkCmdLineModuleDescription.cpp ctkCmdLineModuleDescription_p.h diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.cpp new file mode 100644 index 0000000000..3983b3a198 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.cpp @@ -0,0 +1,93 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleConcurrentHelpers.h" + +#include "ctkCmdLineModuleManager.h" +#include "ctkException.h" + +#include <QUrl> +#include <QDebug> + +//---------------------------------------------------------------------------- +ctkCmdLineModuleConcurrentRegister::ctkCmdLineModuleConcurrentRegister(ctkCmdLineModuleManager* manager, + bool debug) + : ModuleManager(manager), Debug(debug) +{} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleReference ctkCmdLineModuleConcurrentRegister::operator()(const QString& moduleLocation) +{ + return this->operator ()(QUrl::fromLocalFile(moduleLocation)); +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleReference ctkCmdLineModuleConcurrentRegister::operator()(const QUrl& moduleUrl) +{ + try + { + return this->ModuleManager->registerModule(moduleUrl); + } + catch (const ctkException& e) + { + if (this->Debug) + { + qDebug() << e; + } + return ctkCmdLineModuleReference(); + } + catch (...) + { + if (this->Debug) + { + qDebug() << "Registering module" << moduleUrl << "failed with an unknown exception."; + } + return ctkCmdLineModuleReference(); + } +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleConcurrentUnRegister::ctkCmdLineModuleConcurrentUnRegister(ctkCmdLineModuleManager* manager) + : ModuleManager(manager) +{} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleConcurrentUnRegister::operator()(const QString& moduleLocation) +{ + return this->operator ()(QUrl::fromLocalFile(moduleLocation)); +} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleConcurrentUnRegister::operator()(const QUrl& moduleUrl) +{ + return this->operator ()(this->ModuleManager->moduleReference(moduleUrl)); +} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleConcurrentUnRegister::operator()(const ctkCmdLineModuleReference& moduleRef) +{ + if (moduleRef) + { + this->ModuleManager->unregisterModule(moduleRef); + return true; + } + return false; +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h new file mode 100644 index 0000000000..2eac369024 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h @@ -0,0 +1,77 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULECONCURRENTHELPERS_H +#define CTKCMDLINEMODULECONCURRENTHELPERS_H + +#include "ctkCommandLineModulesCoreExport.h" + +#include "ctkCmdLineModuleReference.h" + +class ctkCmdLineModuleManager; + +/** + * \ingroup CommandLineModulesCore + * + * \brief A function object for concurrently adding modules. + */ +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleConcurrentRegister +{ + +public: + + typedef ctkCmdLineModuleReference result_type; + + ctkCmdLineModuleConcurrentRegister(ctkCmdLineModuleManager* manager, bool debug = false); + ctkCmdLineModuleReference operator()(const QString& moduleLocation); + ctkCmdLineModuleReference operator()(const QUrl& moduleUrl); + +private: + + ctkCmdLineModuleManager* ModuleManager; + bool Debug; +}; + +/** + * \ingroup CommandLineModulesCore + * + * \brief A function object for concurrently removing modules. + */ +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleConcurrentUnRegister +{ + +public: + + typedef bool result_type; + + ctkCmdLineModuleConcurrentUnRegister(ctkCmdLineModuleManager* manager); + + bool operator()(const QString& moduleLocation); + bool operator()(const QUrl& moduleUrl); + bool operator()(const ctkCmdLineModuleReference& moduleRef); + +private: + + ctkCmdLineModuleManager* ModuleManager; +}; + + +#endif // CTKCMDLINEMODULECONCURRENTHELPERS_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp index ddd1a7a3b5..0c5e7b5703 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.cpp @@ -21,6 +21,7 @@ #include "ctkCmdLineModuleDirectoryWatcher.h" #include "ctkCmdLineModuleDirectoryWatcher_p.h" #include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleConcurrentHelpers.h" #include "ctkException.h" #include <QObject> @@ -34,72 +35,6 @@ #include <iostream> -//----------------------------------------------------------------------------- -// A function object for concurrently adding modules -namespace { -struct AddModule -{ - typedef ctkCmdLineModuleReference result_type; - - AddModule(ctkCmdLineModuleManager* manager, bool debug = false) - : ModuleManager(manager), Debug(debug) - {} - - ctkCmdLineModuleReference operator()(const QString& moduleLocation) - { - try - { - return this->ModuleManager->registerModule(QUrl::fromLocalFile(moduleLocation)); - } - catch (const ctkException& e) - { - if (this->Debug) - { - qDebug() << e; - } - return ctkCmdLineModuleReference(); - } - catch (...) - { - if (this->Debug) - { - qDebug() << "Registering module" << moduleLocation << "failed with an unknown exception."; - } - return ctkCmdLineModuleReference(); - } - } - - ctkCmdLineModuleManager* ModuleManager; - bool Debug; -}; -} - -//----------------------------------------------------------------------------- -// A function object for concurrently removing modules -namespace { -struct RemoveModule -{ - typedef bool result_type; - - RemoveModule(ctkCmdLineModuleManager* manager) - : ModuleManager(manager) - {} - - bool operator()(const QString& moduleLocation) - { - ctkCmdLineModuleReference ref = this->ModuleManager->moduleReference(QUrl::fromLocalFile(moduleLocation)); - if (ref) - { - this->ModuleManager->unregisterModule(ref); - return true; - } - return false; - } - - ctkCmdLineModuleManager* ModuleManager; -}; -} - //----------------------------------------------------------------------------- // ctkCmdLineModuleDirectoryWatcher methods @@ -388,7 +323,8 @@ void ctkCmdLineModuleDirectoryWatcherPrivate::updateModuleReferences(const QStri //----------------------------------------------------------------------------- QList<ctkCmdLineModuleReference> ctkCmdLineModuleDirectoryWatcherPrivate::loadModules(const QStringList& executables) { - QList<ctkCmdLineModuleReference> refs = QtConcurrent::blockingMapped(executables, AddModule(this->ModuleManager, this->Debug)); + QList<ctkCmdLineModuleReference> refs = QtConcurrent::blockingMapped(executables, + ctkCmdLineModuleConcurrentRegister(this->ModuleManager, this->Debug)); for (int i = 0; i < executables.size(); ++i) { @@ -404,7 +340,7 @@ QList<ctkCmdLineModuleReference> ctkCmdLineModuleDirectoryWatcherPrivate::loadMo //----------------------------------------------------------------------------- void ctkCmdLineModuleDirectoryWatcherPrivate::unloadModules(const QStringList& executables) { - QtConcurrent::blockingMapped(executables, RemoveModule(this->ModuleManager)); + QtConcurrent::blockingMapped(executables, ctkCmdLineModuleConcurrentUnRegister(this->ModuleManager)); foreach(QString executable, executables) { this->MapFileNameToReference.remove(executable); From aba7124d6278e729acb279b2b59807e8b8c26510 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:11:01 +0200 Subject: [PATCH 140/247] Use proper doxygen comment style. --- .../Core/ctkCmdLineModuleFrontend.h | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 03aaa703e3..a9b29dde64 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -50,19 +50,21 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject enum ParameterValueRole { - /* Data returned using this role must not be of any type not supported by - QVariant by default. For complex parameter types (like file, image, - geometry, etc.) the data must be convertible to a QString pointing - to a local resource. + /** + * Data returned using this role must not be of any type not supported by + * QVariant by default. For complex parameter types (like file, image, + * geometry, etc.) the data must be convertible to a QString pointing + * to a local resource. */ LocalResourceRole = 0, - /* This role can be used in custom frontends to return a QVariant - containing for example an in-memory representation of a complex object. - One can then either convert the in-memory representation to a local - resource before running a module such that arbitrary backends relying on - the LocalResourceRole can process the data. Or one creates a custom - backend which knows how to handle QVariants returned by this role. + /** + * This role can be used in custom frontends to return a QVariant + * containing for example an in-memory representation of a complex object. + * One can then either convert the in-memory representation to a local + * resource before running a module such that arbitrary backends relying on + * the LocalResourceRole can process the data. Or one creates a custom + * backend which knows how to handle QVariants returned by this role. */ UserRole = 8 }; From c6668f94d5284b37b37753b87d2eaeb7fa15bbcf Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:11:32 +0200 Subject: [PATCH 141/247] Make the bool conversion operator a const method. --- Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp index 00bce92b8e..86437e9fc0 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp @@ -70,7 +70,7 @@ ctkCmdLineModuleReference &ctkCmdLineModuleReference::operator =(const ctkCmdLin } //---------------------------------------------------------------------------- -ctkCmdLineModuleReference::operator bool() +ctkCmdLineModuleReference::operator bool() const { return !d->RawXmlDescription.isEmpty(); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index 26b7d08710..b067f1d7f6 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -47,7 +47,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference ctkCmdLineModuleReference(const ctkCmdLineModuleReference& ref); ctkCmdLineModuleReference& operator=(const ctkCmdLineModuleReference& ref); - operator bool(); + operator bool() const; ctkCmdLineModuleDescription description() const; From da202b4e9384297e2a51a40727bc58ed329e89ba Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:12:00 +0200 Subject: [PATCH 142/247] Added a qHash overload for ctkCmdLineModuleReference for usage in QHash. --- Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp | 6 ++++++ Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp index 86437e9fc0..2a87210804 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.cpp @@ -104,3 +104,9 @@ ctkCmdLineModuleBackend *ctkCmdLineModuleReference::backend() const { return d->Backend; } + +//---------------------------------------------------------------------------- +uint qHash(const ctkCmdLineModuleReference& moduleRef) +{ + return qHash(moduleRef.d.data()); +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index b067f1d7f6..4ec0e35dc1 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -62,6 +62,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference private: friend class ctkCmdLineModuleManager; + friend uint qHash(const ctkCmdLineModuleReference&); QSharedDataPointer<ctkCmdLineModuleReferencePrivate> d; @@ -69,4 +70,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference Q_DECLARE_METATYPE(ctkCmdLineModuleReference) +CTK_CMDLINEMODULECORE_EXPORT uint qHash(const ctkCmdLineModuleReference& moduleRef); + #endif // CTKCMDLINEMODULEREFERENCE_H From 2964e7806bce6b39d46f604e2d097802050d3a88 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:13:06 +0200 Subject: [PATCH 143/247] Remove entries from the tree if modules are unregistered. --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 1 + .../ctkCmdLineModuleExplorerTreeWidget.cpp | 26 ++++++++++++++++++- .../ctkCmdLineModuleExplorerTreeWidget.h | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index 343b5c3309..9ba6fd77a8 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -76,6 +76,7 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : // If a module is registered via the ModuleManager, add it the tree connect(&moduleManager, SIGNAL(moduleRegistered(ctkCmdLineModuleReference)), ui->modulesTreeWidget, SLOT(addModuleItem(ctkCmdLineModuleReference))); + connect(&moduleManager, SIGNAL(moduleUnregistered(ctkCmdLineModuleReference)), ui->modulesTreeWidget, SLOT(removeModuleItem(ctkCmdLineModuleReference))); // Double-clicking on an item in the tree creates a new tab with the default frontend connect(ui->modulesTreeWidget, SIGNAL(moduleDoubleClicked(ctkCmdLineModuleReference)), this, SLOT(addModuleTab(ctkCmdLineModuleReference))); // React to specific frontend creations diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp index a1cb878e03..af59d5b789 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.cpp @@ -116,7 +116,31 @@ void ctkCmdLineModuleExplorerTreeWidget::addModuleItem(const ctkCmdLineModuleRef rootItem->setText(0, category); TreeWidgetCategories[category] = rootItem; } - new ctkCmdLineModuleTreeWidgetItem(rootItem, moduleRef); + TreeWidgetItems[moduleRef] = new ctkCmdLineModuleTreeWidgetItem(rootItem, moduleRef); +} + +void ctkCmdLineModuleExplorerTreeWidget::removeModuleItem(const ctkCmdLineModuleReference &moduleRef) +{ + QString category = moduleRef.description().category(); + if (category.isEmpty()) + { + category = CATEGORY_UNKNOWN; + } + + + QTreeWidgetItem* treeWidgetItem = TreeWidgetItems.take(moduleRef); + if (treeWidgetItem == NULL) return; + + this->removeItemWidget(treeWidgetItem, 0); + delete treeWidgetItem; + + QTreeWidgetItem* rootItem = TreeWidgetCategories[category]; + if (rootItem && rootItem->childCount() == 0) + { + this->removeItemWidget(rootItem, 0); + TreeWidgetCategories.remove(category); + delete rootItem; + } } void ctkCmdLineModuleExplorerTreeWidget::contextMenuEvent(QContextMenuEvent *event) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h index b610f6d583..ac2e43812e 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTreeWidget.h @@ -44,6 +44,7 @@ class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget void setModuleFrontendFactories(const QList<ctkCmdLineModuleFrontendFactory*>& frontendFactories); Q_SLOT void addModuleItem(const ctkCmdLineModuleReference& moduleRef); + Q_SLOT void removeModuleItem(const ctkCmdLineModuleReference& moduleRef); Q_SIGNAL void moduleDoubleClicked(ctkCmdLineModuleReference moduleRef); Q_SIGNAL void moduleFrontendCreated(ctkCmdLineModuleFrontend* moduleFrontend); @@ -65,6 +66,7 @@ class ctkCmdLineModuleExplorerTreeWidget : public QTreeWidget ctkCmdLineModuleReference ContextReference; QList<ctkCmdLineModuleFrontendFactory*> FrontendFactories; QHash<QString, QTreeWidgetItem*> TreeWidgetCategories; + QHash<ctkCmdLineModuleReference, QTreeWidgetItem*> TreeWidgetItems; QHash<QAction*, ctkCmdLineModuleFrontendFactory*> ActionsToFrontendFactoryMap; }; From 3c491165d01d65ca8c5041b2ca576837afcb65b7 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:14:59 +0200 Subject: [PATCH 144/247] Use CTK settings classes for persisting user values. --- .../CMakeLists.txt | 5 + .../ctkCmdLineModuleExplorerConstants.cpp | 25 +++++ .../ctkCmdLineModuleExplorerConstants.h | 33 ++++++ ...CmdLineModuleExplorerDirectorySettings.cpp | 22 +++- ...tkCmdLineModuleExplorerDirectorySettings.h | 15 ++- ...kCmdLineModuleExplorerDirectorySettings.ui | 105 ++++++++++++++++++ .../ctkCmdLineModuleExplorerMainWindow.cpp | 21 +++- .../ctkCmdLineModuleExplorerMainWindow.h | 2 + ...tkCmdLineModuleExplorerModulesSettings.cpp | 73 ++++++++++++ .../ctkCmdLineModuleExplorerModulesSettings.h | 49 ++++++++ ...ctkCmdLineModuleExplorerModulesSettings.ui | 91 +++++++++++++++ 11 files changed, 433 insertions(+), 8 deletions(-) create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.cpp create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.h create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.ui create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.cpp create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.h create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.ui diff --git a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt index 0da7d6cfa6..9d27c06086 100644 --- a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt +++ b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt @@ -6,9 +6,11 @@ project(ctkCommandLineModuleExplorer) set(KIT_SRCS ctkCommandLineModuleExplorerMain.cpp + ctkCmdLineModuleExplorerConstants.cpp ctkCmdLineModuleExplorerDirectorySettings.cpp ctkCmdLineModuleExplorerMainWindow.h ctkCmdLineModuleExplorerMainWindow.cpp + ctkCmdLineModuleExplorerModulesSettings.cpp ctkCmdLineModuleExplorerProgressWidget.cpp ctkCmdLineModuleExplorerTabList.cpp ctkCmdLineModuleExplorerTreeWidget.cpp @@ -17,6 +19,7 @@ set(KIT_SRCS # Headers that should run through moc set(KIT_MOC_SRCS ctkCmdLineModuleExplorerMainWindow.h + ctkCmdLineModuleExplorerModulesSettings.h ctkCmdLineModuleExplorerProgressWidget.h ctkCmdLineModuleExplorerTabList.h ctkCmdLineModuleExplorerTreeWidget.h @@ -24,7 +27,9 @@ set(KIT_MOC_SRCS # UI files set(KIT_UI_FORMS + ctkCmdLineModuleExplorerDirectorySettings.ui ctkCmdLineModuleExplorerMainWindow.ui + ctkCmdLineModuleExplorerModulesSettings.ui ctkCmdLineModuleExplorerProgressWidget.ui ) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.cpp new file mode 100644 index 0000000000..aed1e1d8be --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.cpp @@ -0,0 +1,25 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleExplorerConstants.h" + +const QString ctkCmdLineModuleExplorerConstants::KEY_SEARCH_PATHS = "ModuleSearchPaths"; +const QString ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES = "RegisteredModules"; diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.h new file mode 100644 index 0000000000..a12fff548d --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerConstants.h @@ -0,0 +1,33 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLORERCONSTANTS_H +#define CTKCMDLINEMODULEEXPLORERCONSTANTS_H + +#include <QString> + +struct ctkCmdLineModuleExplorerConstants +{ + static const QString KEY_SEARCH_PATHS; + static const QString KEY_REGISTERED_MODULES; +}; + +#endif // CTKCMDLINEMODULEEXPLORERCONSTANTS_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp index 4bbb619885..7dfb8a87e9 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.cpp @@ -20,14 +20,28 @@ =============================================================================*/ #include "ctkCmdLineModuleExplorerDirectorySettings.h" +#include "ctkCmdLineModuleExplorerConstants.h" #include <ctkPathListWidget.h> +#include <ctkCmdLineModuleDirectoryWatcher.h> #include <QVBoxLayout> -ctkCmdLineModuleExplorerDirectorySettings::ctkCmdLineModuleExplorerDirectorySettings() +ctkCmdLineModuleExplorerDirectorySettings::ctkCmdLineModuleExplorerDirectorySettings(ctkCmdLineModuleDirectoryWatcher *directoryWatcher) + : DirectoryWatcher(directoryWatcher) { - this->setWindowTitle("Module Paths"); - this->setLayout(new QVBoxLayout()); - this->layout()->addWidget(new ctkPathListWidget()); + this->setupUi(this); + + this->PathListButtonsWidget->init(this->PathListWidget); + + this->registerProperty(ctkCmdLineModuleExplorerConstants::KEY_SEARCH_PATHS, + this->PathListWidget, "paths", SIGNAL(pathsChanged(QStringList,QStringList))); +} + +void ctkCmdLineModuleExplorerDirectorySettings::applySettings() +{ + QVariant newSearchPaths = this->propertyValue(ctkCmdLineModuleExplorerConstants::KEY_SEARCH_PATHS); + this->DirectoryWatcher->setDirectories(newSearchPaths.toStringList()); + + ctkSettingsPanel::applySettings(); } diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h index 486da304e1..888e0b2cd6 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.h @@ -24,14 +24,25 @@ #include <ctkSettingsPanel.h> +#include "ui_ctkCmdLineModuleExplorerDirectorySettings.h" + +class ctkCmdLineModuleDirectoryWatcher; + /** * \class ctkCmdLineModuleExplorerDirectorySettings * \brief Example application settings panel. */ -class ctkCmdLineModuleExplorerDirectorySettings : public ctkSettingsPanel +class ctkCmdLineModuleExplorerDirectorySettings : public ctkSettingsPanel, public Ui::ctkCmdLineModuleExplorerDirectorySettings { public: - ctkCmdLineModuleExplorerDirectorySettings(); + ctkCmdLineModuleExplorerDirectorySettings(ctkCmdLineModuleDirectoryWatcher* directoryWatcher); + + void applySettings(); + +private: + + ctkCmdLineModuleDirectoryWatcher* DirectoryWatcher; + }; #endif // CTKCMDLINEMODULEEXPLORERDIRECTORYSETTINGS_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.ui new file mode 100644 index 0000000000..180bf290fc --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerDirectorySettings.ui @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ctkCmdLineModuleExplorerDirectorySettings</class> + <widget class="QWidget" name="ctkCmdLineModuleExplorerDirectorySettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Search Paths</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Module Search Paths</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="1"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="ctkPathListButtonsWidget" name="PathListButtonsWidget"> + <property name="buttonsAutoRaise"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="ctkPathListWidget" name="PathListWidget"> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + <property name="mode"> + <enum>ctkPathListWidget::DirectoriesOnly</enum> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>The following list of paths will be searched for executables which provide a XML parameter description when called with a "--xml" command line argument:</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ctkPathListButtonsWidget</class> + <extends>QWidget</extends> + <header>ctkPathListButtonsWidget.h</header> + </customwidget> + <customwidget> + <class>ctkPathListWidget</class> + <extends>QListView</extends> + <header>ctkPathListWidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index 9ba6fd77a8..c2f6bb036e 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -23,10 +23,13 @@ #include "ui_ctkCmdLineModuleExplorerMainWindow.h" #include "ctkCmdLineModuleExplorerDirectorySettings.h" +#include "ctkCmdLineModuleExplorerModulesSettings.h" #include "ctkCmdLineModuleExplorerTabList.h" #include "ctkCmdLineModuleExplorerProgressWidget.h" +#include "ctkCmdLineModuleExplorerConstants.h" #include <ctkCmdLineModuleManager.h> +#include <ctkCmdLineModuleConcurrentHelpers.h> #include <ctkCmdLineModuleDescription.h> #include <ctkCmdLineModuleFrontendFactoryQtGui.h> #include <ctkCmdLineModuleFrontendFactoryQtWebKit.h> @@ -36,6 +39,7 @@ #include <ctkSettingsDialog.h> +#include <QtConcurrentMap> #include <QDesktopServices> #include <QMessageBox> #include <QFutureSynchronizer> @@ -52,6 +56,8 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : { ui->setupUi(this); + settings.restoreState(this->objectName(), *this); + // Frontends moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtGui; moduleFrontendFactories << new ctkCmdLineModuleFrontendFactoryQtWebKit; @@ -70,7 +76,10 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : } settingsDialog = new ctkSettingsDialog(this); - settingsDialog->addPanel(new ctkCmdLineModuleExplorerDirectorySettings()); + settings.restoreState(settingsDialog->objectName(), *settingsDialog); + settingsDialog->setSettings(&settings); + settingsDialog->addPanel(new ctkCmdLineModuleExplorerDirectorySettings(&directoryWatcher)); + settingsDialog->addPanel(new ctkCmdLineModuleExplorerModulesSettings(&moduleManager)); tabList.reset(new ctkCmdLineModuleExplorerTabList(ui->mainTabWidget)); @@ -101,8 +110,13 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : moduleManager.registerModule(fpModule); } + // Register persistent modules + QtConcurrent::mapped(settings.value(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(), + ctkCmdLineModuleConcurrentRegister(&moduleManager)); + + // Start watching directories directoryWatcher.setDebug(true); - directoryWatcher.setDirectories(QStringList(QCoreApplication::applicationDirPath())); + directoryWatcher.setDirectories(settings.value(ctkCmdLineModuleExplorerConstants::KEY_SEARCH_PATHS).toStringList()); moduleTabActivated(NULL); @@ -113,6 +127,9 @@ ctkCLModuleExplorerMainWindow::~ctkCLModuleExplorerMainWindow() { qDeleteAll(moduleBackends); qDeleteAll(moduleFrontendFactories); + + settings.saveState(*this, this->objectName()); + settings.saveState(*settingsDialog, settingsDialog->objectName()); } void ctkCLModuleExplorerMainWindow::addModule(const QUrl &location) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h index 9bf5247b70..87c213b125 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h @@ -25,6 +25,7 @@ #include <ctkCmdLineModuleManager.h> #include <ctkCmdLineModuleDirectoryWatcher.h> #include <ctkCmdLineModuleFuture.h> +#include <ctkSettings.h> #include <QMainWindow> #include <QTimer> @@ -92,6 +93,7 @@ protected Q_SLOTS: ctkCmdLineModuleDirectoryWatcher directoryWatcher; + ctkSettings settings; ctkSettingsDialog* settingsDialog; }; diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.cpp new file mode 100644 index 0000000000..6d04d305d3 --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.cpp @@ -0,0 +1,73 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleExplorerModulesSettings.h" +#include "ctkCmdLineModuleExplorerConstants.h" + +#include "ui_ctkCmdLineModuleExplorerModulesSettings.h" + +#include <ctkCmdLineModuleManager.h> +#include <ctkCmdLineModuleConcurrentHelpers.h> + +#include <QUrl> +#include <QtConcurrentMap> + +ctkCmdLineModuleExplorerModulesSettings::ctkCmdLineModuleExplorerModulesSettings(ctkCmdLineModuleManager *moduleManager) + : ui(new Ui::ctkCmdLineModuleExplorerModulesSettings) + , ModuleManager(moduleManager) +{ + ui->setupUi(this); + + ui->PathListButtonsWidget->init(ui->PathListWidget); + + this->registerProperty(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES, + ui->PathListWidget, "paths", SIGNAL(pathsChanged(QStringList,QStringList))); +} + +ctkCmdLineModuleExplorerModulesSettings::~ctkCmdLineModuleExplorerModulesSettings() +{ + delete ui; +} + +void ctkCmdLineModuleExplorerModulesSettings::applySettings() +{ + QStringList oldModules = this->previousPropertyValue(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(); + QStringList newModules = this->propertyValue(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(); + + QStringList removedModules; + QStringList addedModules = newModules; + foreach(const QString& oldModule, oldModules) + { + if (!newModules.contains(oldModule)) + { + removedModules << oldModule; + } + else + { + addedModules.removeAll(oldModule); + } + } + + QtConcurrent::mapped(removedModules, ctkCmdLineModuleConcurrentUnRegister(this->ModuleManager)); + QtConcurrent::mapped(addedModules, ctkCmdLineModuleConcurrentRegister(this->ModuleManager)); + + ctkSettingsPanel::applySettings(); +} diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.h new file mode 100644 index 0000000000..31b904eb8d --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.h @@ -0,0 +1,49 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLORERMODULESSETTINGS_H +#define CTKCMDLINEMODULEEXPLORERMODULESSETTINGS_H + +#include <ctkSettingsPanel.h> + +class ctkCmdLineModuleManager; + +namespace Ui { +class ctkCmdLineModuleExplorerModulesSettings; +} + +class ctkCmdLineModuleExplorerModulesSettings : public ctkSettingsPanel +{ + Q_OBJECT + +public: + explicit ctkCmdLineModuleExplorerModulesSettings(ctkCmdLineModuleManager* moduleManager); + ~ctkCmdLineModuleExplorerModulesSettings(); + + void applySettings(); + +private: + Ui::ctkCmdLineModuleExplorerModulesSettings *ui; + + ctkCmdLineModuleManager* ModuleManager; +}; + +#endif // CTKCMDLINEMODULEEXPLORERMODULESSETTINGS_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.ui new file mode 100644 index 0000000000..ac7ac7c78b --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerModulesSettings.ui @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ctkCmdLineModuleExplorerModulesSettings</class> + <widget class="QWidget" name="ctkCmdLineModuleExplorerModulesSettings"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Registered Modules</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Registered Modules</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="ctkPathListWidget" name="PathListWidget"> + <property name="mode"> + <enum>ctkPathListWidget::FilesOnly</enum> + </property> + <property name="fileOptions"> + <set>ctkPathListWidget::Executable|ctkPathListWidget::Exists|ctkPathListWidget::Readable</set> + </property> + </widget> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="ctkPathListButtonsWidget" name="PathListButtonsWidget"> + <property name="buttonsAutoRaise"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ctkPathListButtonsWidget</class> + <extends>QWidget</extends> + <header>ctkPathListButtonsWidget.h</header> + </customwidget> + <customwidget> + <class>ctkPathListWidget</class> + <extends>QListView</extends> + <header>ctkPathListWidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> From dfc31a30ee50ddc5929485b481ab0a90a4fdca67 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 01:54:30 +0200 Subject: [PATCH 145/247] Fixed Windows warnings and linker error. --- Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt | 1 - .../Core/ctkCmdLineModuleDefaultPathBuilder.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt index 186c6faeba..24df0b3223 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt +++ b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt @@ -22,7 +22,6 @@ set(KIT_SRCS # Headers that should run through moc set(KIT_MOC_SRCS - ctkCmdLineModuleProcessTask.h ctkCmdLineModuleProcessWatcher_p.h ) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h index 26feb7ed20..ff7b722ab9 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h @@ -25,7 +25,7 @@ #include <QStringList> #include <QScopedPointer> -class ctkCmdLineModuleDefaultPathBuilderPrivate; +struct ctkCmdLineModuleDefaultPathBuilderPrivate; /** * \class ctkCmdLineModuleDefaultPathBuilder diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index 4ec0e35dc1..ea9e500cdc 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -62,7 +62,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference private: friend class ctkCmdLineModuleManager; - friend uint qHash(const ctkCmdLineModuleReference&); + friend uint CTK_CMDLINEMODULECORE_EXPORT qHash(const ctkCmdLineModuleReference&); QSharedDataPointer<ctkCmdLineModuleReferencePrivate> d; @@ -70,6 +70,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference Q_DECLARE_METATYPE(ctkCmdLineModuleReference) -CTK_CMDLINEMODULECORE_EXPORT uint qHash(const ctkCmdLineModuleReference& moduleRef); +uint CTK_CMDLINEMODULECORE_EXPORT qHash(const ctkCmdLineModuleReference& moduleRef); #endif // CTKCMDLINEMODULEREFERENCE_H From 412abe63033a36844a5150e607aa6c968f675204 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 14:47:31 +0200 Subject: [PATCH 146/247] Ignore git specific files when creating archives. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 7c6ba581c4..3f33d1ec78 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.ts text +.git* export-ignore From 52f6625350ba7becc6c88a53bcd3957d93511601 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Tue, 28 Aug 2012 17:53:33 +0200 Subject: [PATCH 147/247] Simplified tests by using QTestLib. --- .../Core/Testing/Cpp/CMakeLists.txt | 3 + ...ctkCmdLineModuleXmlProgressWatcherTest.cpp | 85 +++--- .../ctkCmdLineModuleQtXslTransformTest.cpp | 25 +- .../Testing/Cpp/CMakeLists.txt | 11 +- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 256 ++++++------------ 5 files changed, 140 insertions(+), 240 deletions(-) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 9d51a8b184..679f1db30f 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -22,6 +22,9 @@ include_directories( set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) +QT4_GENERATE_MOCS( + ctkCmdLineModuleXmlProgressWatcherTest.cpp +) set(Tests_UI_CPP) if(TEST_UI_FORMS) QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp index b1d3582b6b..6b3c2f4a57 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleXmlProgressWatcherTest.cpp @@ -24,15 +24,17 @@ #include "ctkCmdLineModuleSignalTester.h" +#include "ctkTest.h" + #include <QCoreApplication> #include <QBuffer> #include <QDataStream> #include <QDebug> -#include <cstdlib> namespace { +//----------------------------------------------------------------------------- // Custom signal tester class SignalTester : public ctkCmdLineModuleSignalTester { @@ -82,7 +84,21 @@ class SignalTester : public ctkCmdLineModuleSignalTester float accumulatedProgress; }; -bool xmlProgressWatcherTestSignalsAndValues() +} + +//----------------------------------------------------------------------------- +class ctkCmdLineModuleXmlProgressWatcherTester : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void testSignalsAndValues(); + void testMalformedXml(); +}; + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleXmlProgressWatcherTester::testSignalsAndValues() { // Test data QByteArray filterStart = "<filter-start>\n" @@ -106,14 +122,11 @@ bool xmlProgressWatcherTestSignalsAndValues() signalTester.connect(&progressWatcher, SIGNAL(filterXmlError(QString)), &signalTester, SLOT(filterXmlError(QString))); buffer.write(filterStart); - QCoreApplication::processEvents(); buffer.write(filterProgress.arg(0.3).toLatin1()); - QCoreApplication::processEvents(); buffer.write(filterProgress.arg(0.6).toLatin1()); - QCoreApplication::processEvents(); buffer.write(filterProgress.arg(0.9).toLatin1()); - QCoreApplication::processEvents(); buffer.write(filterEnd); + QCoreApplication::processEvents(); QList<QString> expectedSignals; @@ -126,24 +139,16 @@ bool xmlProgressWatcherTestSignalsAndValues() if (!signalTester.error.isEmpty()) { qDebug() << signalTester.error; - return false; - } - - if (!signalTester.checkSignals(expectedSignals)) - { - return false; + QFAIL("XML parsing error"); } - if (signalTester.accumulatedProgress != 1.8f) - { - qDebug() << "Progress information wrong. Expected 1.8, got" << signalTester.accumulatedProgress; - return false; - } + QVERIFY(signalTester.checkSignals(expectedSignals)); - return true; + QCOMPARE(signalTester.accumulatedProgress, 1.8f); } -bool xmlProgressWatcherTestMalformedXml() +//----------------------------------------------------------------------------- +void ctkCmdLineModuleXmlProgressWatcherTester::testMalformedXml() { // Test data QByteArray filterOutput = "<filter-start>\n" @@ -170,8 +175,8 @@ bool xmlProgressWatcherTestMalformedXml() signalTester.connect(&progressWatcher, SIGNAL(filterXmlError(QString)), &signalTester, SLOT(filterXmlError(QString))); buffer.write(filterOutput); - QCoreApplication::processEvents(); + QCoreApplication::processEvents(); QList<QString> expectedSignals; expectedSignals << "filter.xmlError"; @@ -179,41 +184,15 @@ bool xmlProgressWatcherTestMalformedXml() expectedSignals << "filter.progress"; expectedSignals << "filter.finished"; - if (!signalTester.error.isEmpty()) - { - qDebug() << signalTester.error; - //return false; - } - - if (!signalTester.checkSignals(expectedSignals)) - { - return false; - } + QVERIFY(!signalTester.error.isEmpty()); + qDebug() << signalTester.error; - if (signalTester.accumulatedProgress != 0.5f) - { - qDebug() << "Progress information wrong. Expected 1.8, got" << signalTester.accumulatedProgress; - return false; - } + QVERIFY(signalTester.checkSignals(expectedSignals)); - return true; + QCOMPARE(signalTester.accumulatedProgress, 0.5f); } -} -int ctkCmdLineModuleXmlProgressWatcherTest(int argc, char* argv[]) -{ - QCoreApplication app(argc, argv); - - if (!xmlProgressWatcherTestSignalsAndValues()) - { - return EXIT_FAILURE; - } - - if (!xmlProgressWatcherTestMalformedXml()) - { - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleXmlProgressWatcherTest) +#include "moc_ctkCmdLineModuleXmlProgressWatcherTest.cpp" diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp index c3264c4111..c043f917b5 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleQtXslTransformTest.cpp @@ -34,6 +34,9 @@ class ctkCmdLineModuleQtXslTransformTester: public QObject { Q_OBJECT private slots: + + void initTestCase(); + void testTransform(); void testTransform_data(); @@ -170,6 +173,14 @@ QString integerWidgetSpinBoxFooter = ; +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleQtXslTransformTester::initTestCase() +{ + // Introduce a dummy linker dependency to CTKCommandLineModulesFrontendQtGui to + // get access to the ctkCmdLineModuleXmlToQtUi.xsl resource. + ctkCmdLineModuleFrontendFactoryQtGui guiFactory; +} + // ---------------------------------------------------------------------------- void ctkCmdLineModuleQtXslTransformTester::testTransform() { @@ -452,17 +463,5 @@ void ctkCmdLineModuleQtXslTransformTester::testXslExtraTransformation_data() } // ---------------------------------------------------------------------------- -//CTK_TEST_MAIN(ctkCmdLineModuleQtXslTransformTest) -int ctkCmdLineModuleQtXslTransformTest(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - QTEST_DISABLE_KEYPAD_NAVIGATION - - // Introduce a dummy linker dependency to CTKCommandLineModulesFrontendQtGui to - // get access to the ctkCmdLineModuleXmlToQtUi.xsl resource. - ctkCmdLineModuleFrontendFactoryQtGui guiFactory; - - ctkCmdLineModuleQtXslTransformTester tc; - return QTest::qExec(&tc, argc, argv); -} +CTK_TEST_MAIN(ctkCmdLineModuleQtXslTransformTest) #include "moc_ctkCmdLineModuleQtXslTransformTest.cpp" diff --git a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt index e98d39d579..b09f3eabe7 100644 --- a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt @@ -2,6 +2,7 @@ set(KIT CTKCommandLineModules) set(LIBRARY_NAME ${KIT}) set(_test_srcs) +set(_test_mocs) if(CTK_LIB_CommandLineModules/Frontend/QtGui) set(QT_USE_QTUITOOLS 1) @@ -9,12 +10,11 @@ if(CTK_LIB_CommandLineModules/Frontend/QtGui) if(CTK_LIB_CommandLineModules/Backend/LocalProcess) list(APPEND _test_srcs ctkCmdLineModuleFutureTest.cpp) + list(APPEND _test_mocs ctkCmdLineModuleFutureTest.cpp) endif() if(CTK_LIB_CommandLineModules/Backend/FunctionPointer) list(APPEND _test_srcs ctkCmdLineModuleQtCustomizationTest.cpp) - QT4_GENERATE_MOCS( - ctkCmdLineModuleQtCustomizationTest.cpp - ) + list(APPEND _test_mocs ctkCmdLineModuleQtCustomizationTest.cpp) endif() endif() @@ -65,6 +65,11 @@ endif() set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) + +if(_test_mocs) + QT4_GENERATE_MOCS(${_test_mocs}) +endif() + set(Tests_UI_CPP) if(TEST_UI_FORMS) QT4_WRAP_UI(Tests_UI_CPP ${Tests_UI_FORMS}) diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index dfb74e3c58..3e872c6ce7 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -32,32 +32,15 @@ #include "ctkCmdLineModuleBackendLocalProcess.h" +#include "ctkTest.h" + #include <QVariant> #include <QCoreApplication> #include <QDebug> #include <QFutureWatcher> -#include <cstdlib> - - -#ifdef Q_OS_WIN -#include <windows.h> -#else -#include <time.h> -#endif - -void sleep_ms(int ms) -{ -#ifdef Q_OS_WIN - Sleep(ms); -#else - struct timespec nanostep; - nanostep.tv_sec = ms / 1000; - nanostep.tv_nsec = ((ms % 1000) * 1000.0 * 1000.0); - nanosleep(&nanostep, NULL); -#endif -} +//----------------------------------------------------------------------------- class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFactory { public: @@ -97,10 +80,58 @@ class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFac virtual QString description() const { return "A mock-up factory for testing."; } }; -bool futureTestStartFinish(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) +//----------------------------------------------------------------------------- +class ctkCmdLineModuleFutureTester : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void initTestCase(); + + void init(); + void cleanup(); + + void testStartFinish(); + void testProgress(); + void testPauseAndCancel(); + void testError(); + +private: + + ctkCmdLineModuleFrontendMockupFactory factory; + ctkCmdLineModuleBackendLocalProcess backend; + + ctkCmdLineModuleManager manager; + + ctkCmdLineModuleReference moduleRef; + ctkCmdLineModuleFrontend* frontend; +}; + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::initTestCase() +{ + manager.registerBackend(&backend); + + QUrl moduleUrl = QUrl::fromLocalFile(QCoreApplication::applicationDirPath() + "/ctkCmdLineModuleTestBed"); + moduleRef = manager.registerModule(moduleUrl); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::init() +{ + frontend = factory.create(moduleRef); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::cleanup() { - qDebug() << "Testing ctkCmdLineModuleFuture start/finish signals."; + delete frontend; +} +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::testStartFinish() +{ QList<QString> expectedSignals; expectedSignals.push_back("module.started"); expectedSignals.push_back("module.finished"); @@ -111,29 +142,17 @@ bool futureTestStartFinish(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFro QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - ctkCmdLineModuleFuture future = manager->run(frontend); + ctkCmdLineModuleFuture future = manager.run(frontend); watcher.setFuture(future); + future.waitForFinished(); - try - { - future.waitForFinished(); - } - catch (const ctkCmdLineModuleRunException& e) - { - qDebug() << e; - return false; - } - - // process pending events QCoreApplication::processEvents(); - - return signalTester.checkSignals(expectedSignals); + QVERIFY(signalTester.checkSignals(expectedSignals)); } -bool futureTestProgress(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::testProgress() { - qDebug() << "Testing ctkCmdLineModuleFuture progress signals."; - QList<QString> expectedSignals; expectedSignals.push_back("module.started"); // this signal is send when connecting a QFutureWatcher to @@ -162,30 +181,20 @@ bool futureTestProgress(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFronte QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); frontend->setValue("numOutputsVar", 1); - ctkCmdLineModuleFuture future = manager->run(frontend); + ctkCmdLineModuleFuture future = manager.run(frontend); watcher.setFuture(future); - try - { - future.waitForFinished(); - } - catch (const ctkCmdLineModuleRunException& e) - { - qDebug() << e; - return false; - } + future.waitForFinished(); // process pending events QCoreApplication::processEvents(); - return signalTester.checkSignals(expectedSignals); + QVERIFY(signalTester.checkSignals(expectedSignals)); } -bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::testPauseAndCancel() { - qDebug() << "Testing ctkCmdLineModuleFuture pause and cancel capabilities"; - - ctkCmdLineModuleSignalTester signalTester; QFutureWatcher<ctkCmdLineModuleResult> watcher; @@ -196,7 +205,7 @@ bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModule QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); frontend->setValue("runtimeVar", 60); - ctkCmdLineModuleFuture future = manager->run(frontend); + ctkCmdLineModuleFuture future = manager.run(frontend); watcher.setFuture(future); QList<QString> expectedSignals; @@ -214,154 +223,59 @@ bool futureTestPauseAndCancel(ctkCmdLineModuleManager* manager, ctkCmdLineModule } expectedSignals.push_back("module.finished"); - sleep_ms(500); + QTest::qWait(100); - QCoreApplication::processEvents(); future.pause(); - sleep_ms(500); - QCoreApplication::processEvents(); + QTest::qWait(100); + QVERIFY(future.isRunning()); if (future.canPause()) { - if (!(future.isPaused() && future.isRunning())) - { - qDebug() << "Pause state wrong"; - future.setPaused(false); - future.cancel(); - QCoreApplication::processEvents(); - future.waitForFinished(); - return false; - } + QVERIFY(future.isPaused()); } future.togglePaused(); - QCoreApplication::processEvents(); - sleep_ms(500); + QTest::qWait(100); - if (future.isPaused() && future.isRunning()) - { - qDebug() << "Pause state wrong (module is paused, but it shouldn't be)"; - future.cancel(); - QCoreApplication::processEvents(); - future.waitForFinished(); - return false; - } + QVERIFY(!future.isPaused()); + QVERIFY(future.isRunning()); - try - { - future.cancel(); - QCoreApplication::processEvents(); - future.waitForFinished(); - } - catch (const ctkCmdLineModuleRunException& e) - { - qDebug() << e; - return false; - } + future.cancel(); + future.waitForFinished(); // process pending events QCoreApplication::processEvents(); - if (!signalTester.checkSignals(expectedSignals)) - { - return false; - } + QVERIFY(future.isCanceled()); + QVERIFY(future.isFinished()); - if (!(future.isCanceled() && future.isFinished())) - { - qDebug() << "Cancel state wrong"; - return false; - } - return true; + QVERIFY(signalTester.checkSignals(expectedSignals)); } -bool futureTestError(ctkCmdLineModuleManager* manager, ctkCmdLineModuleFrontend* frontend) +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::testError() { - qDebug() << "Testing ctkCmdLineModuleFuture error reporting."; - frontend->setValue("fileVar", "output1"); frontend->setValue("exitCodeVar", 24); frontend->setValue("errorTextVar", "Some error occured\n"); QFutureWatcher<ctkCmdLineModuleResult> watcher; - ctkCmdLineModuleFuture future = manager->run(frontend); + ctkCmdLineModuleFuture future = manager.run(frontend); watcher.setFuture(future); try { future.waitForFinished(); - return EXIT_FAILURE; + QFAIL("Expected exception not thrown."); } catch (const ctkCmdLineModuleRunException& e) { - Q_ASSERT_X(e.errorCode() == 24, __FUNCTION__, "Error code mismatch"); - Q_ASSERT_X(e.errorString() == "Some error occured\n", __FUNCTION__, "Error text mismatch"); + QVERIFY2(e.errorCode() == 24, "Test matching error code"); + QVERIFY2(e.errorString() == "Some error occured\n", "Error text mismatch"); } - - // process pending events - QCoreApplication::processEvents(); - - return true; } -int ctkCmdLineModuleFutureTest(int argc, char* argv[]) -{ - QCoreApplication app(argc, argv); - - ctkCmdLineModuleFrontendMockupFactory factory; - ctkCmdLineModuleBackendLocalProcess backend; - - ctkCmdLineModuleManager manager; - manager.registerBackend(&backend); - - QUrl moduleUrl = QUrl::fromLocalFile(app.applicationDirPath() + "/ctkCmdLineModuleTestBed"); - ctkCmdLineModuleReference moduleRef; - try - { - moduleRef = manager.registerModule(moduleUrl); - } - catch (const ctkException& e) - { - qCritical() << "Module at" << moduleUrl << "could not be registered: " << e; - } - - { - QScopedPointer<ctkCmdLineModuleFrontend> frontend(factory.create(moduleRef)); - if (!futureTestStartFinish(&manager, frontend.data())) - { - return EXIT_FAILURE; - } - } - - { - QScopedPointer<ctkCmdLineModuleFrontend> frontend(factory.create(moduleRef)); - if (!futureTestProgress(&manager, frontend.data())) - { - return EXIT_FAILURE; - } - } - - { - QScopedPointer<ctkCmdLineModuleFrontend> frontend(factory.create(moduleRef)); - if (!futureTestError(&manager, frontend.data())) - { - return EXIT_FAILURE; - } - } - - { - QScopedPointer<ctkCmdLineModuleFrontend> frontend(factory.create(moduleRef)); - if (!futureTestPauseAndCancel(&manager, frontend.data())) - { - return EXIT_FAILURE; - } - } - - // if (!futureTestResultReady(frontend.data())) - // { - // return EXIT_FAILURE; - // } - - return EXIT_SUCCESS; -} +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleFutureTest) +#include "moc_ctkCmdLineModuleFutureTest.cpp" From 4141050532dd3f5a1b08398d95971a233d0ce3ac Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Wed, 29 Aug 2012 14:46:27 +0200 Subject: [PATCH 148/247] Added enhanced ctkCmdLineModuleFutureWatcher class for watching output. --- .../ctkCmdLineModuleProcessTask.cpp | 8 +- .../ctkCmdLineModuleProcessWatcher.cpp | 16 ++ .../ctkCmdLineModuleProcessWatcher_p.h | 3 + Libs/CommandLineModules/Core/CMakeLists.txt | 7 +- .../Core/ctkCmdLineModuleFrontend.h | 17 +- .../Core/ctkCmdLineModuleFuture.cpp | 57 +++++ .../Core/ctkCmdLineModuleFuture.h | 20 +- .../Core/ctkCmdLineModuleFutureInterface.cpp | 201 ++++++++++++++++ .../Core/ctkCmdLineModuleFutureInterface.h | 67 +++--- .../Core/ctkCmdLineModuleFutureInterface_p.h | 90 ++++++++ .../Core/ctkCmdLineModuleFutureWatcher.cpp | 216 ++++++++++++++++++ .../Core/ctkCmdLineModuleFutureWatcher.h | 86 +++++++ .../Core/ctkCmdLineModuleManager.cpp | 1 + .../ctkCmdLineModuleXmlProgressWatcher.cpp | 40 +++- .../Core/ctkCmdLineModuleXmlProgressWatcher.h | 6 + .../Cpp/ctkCmdLineModuleFutureTest.cpp | 166 ++++++++++---- .../Cpp/ctkCmdLineModuleSignalTester.cpp | 87 +++++-- .../Cpp/ctkCmdLineModuleSignalTester.h | 25 +- .../TestBed/ctkCmdLineModuleTestBed.cpp | 16 +- .../TestBed/ctkCmdLineModuleTestBed.xml | 2 +- 20 files changed, 1000 insertions(+), 131 deletions(-) create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface_p.h create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp create mode 100644 Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp index 02498804c1..178b9b9fe6 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp @@ -90,16 +90,12 @@ void ctkCmdLineModuleProcessTask::run() localLoop.exec(); - if (process.error() != QProcess::UnknownError) + if (process.error() != QProcess::UnknownError || process.exitCode() != 0) { this->reportException(ctkCmdLineModuleRunException(d->Location, process.exitCode(), process.errorString())); } - else if (process.exitCode() != 0) - { - this->reportException(ctkCmdLineModuleRunException(d->Location, process.exitCode(), process.readAllStandardError())); - } - this->setProgressValueAndText(1000, process.readAllStandardError()); + this->setProgressValue(1000); //this->reportResult(result); this->reportFinished(); diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp index fa450b857a..42900a2391 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp @@ -42,6 +42,9 @@ ctkCmdLineModuleProcessWatcher::ctkCmdLineModuleProcessWatcher(QProcess& process connect(&processXmlWatcher, SIGNAL(filterFinished(QString)), SLOT(filterFinished(QString))); connect(&processXmlWatcher, SIGNAL(filterXmlError(QString)), SLOT(filterXmlError(QString))); + connect(&processXmlWatcher, SIGNAL(outputDataAvailable(QByteArray)), SLOT(outputDataAvailable(QByteArray))); + connect(&processXmlWatcher, SIGNAL(errorDataAvailable(QByteArray)), SLOT(errorDataAvailable(QByteArray))); + connect(&futureWatcher, SIGNAL(canceled()), SLOT(cancelProcess())); #ifdef Q_OS_UNIX connect(&futureWatcher, SIGNAL(resumed()), SLOT(resumeProcess())); @@ -122,6 +125,19 @@ void ctkCmdLineModuleProcessWatcher::cancelProcess() process.terminate(); } +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::outputDataAvailable(const QByteArray &outputData) +{ + futureInterface.reportOutputData(outputData); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleProcessWatcher::errorDataAvailable(const QByteArray &errorData) +{ + futureInterface.reportErrorData(errorData); +} + +//---------------------------------------------------------------------------- int ctkCmdLineModuleProcessWatcher::updateProgress(float progress) { progressValue = static_cast<int>(progress * 1000.0f); diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h index 7cc88d34c2..fe6703eabe 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher_p.h @@ -59,6 +59,9 @@ protected Q_SLOTS: void resumeProcess(); void cancelProcess(); + void outputDataAvailable(const QByteArray& outputData); + void errorDataAvailable(const QByteArray& errorData); + private: int updateProgress(float progress); diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index fe17456b99..922ea6137d 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -25,8 +25,10 @@ set(KIT_SRCS ctkCmdLineModuleDirectoryWatcher_p.h ctkCmdLineModuleFrontend.cpp ctkCmdLineModuleFrontendFactory.cpp - ctkCmdLineModuleFuture.h - ctkCmdLineModuleFutureInterface.h + ctkCmdLineModuleFuture.cpp + ctkCmdLineModuleFutureInterface_p.h + ctkCmdLineModuleFutureInterface.cpp + ctkCmdLineModuleFutureWatcher.cpp ctkCmdLineModuleManager.cpp ctkCmdLineModuleParameter.cpp ctkCmdLineModuleParameterGroup.cpp @@ -51,6 +53,7 @@ set(KIT_MOC_SRCS ctkCmdLineModuleDirectoryWatcher.h ctkCmdLineModuleDirectoryWatcher_p.h ctkCmdLineModuleFrontend.h + ctkCmdLineModuleFutureWatcher.h ctkCmdLineModuleManager.h ) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index a9b29dde64..ec7679bd91 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -104,7 +104,12 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject /** * @brief Return the ctkCmdLineModuleFuture, derived from QFuture to - * provide asynchronous processing. + * provide asynchronous processing and interaction with the running frontend. + * + * Note that the future returned by this method will be different after the + * frontend was started. Either use isRunning() to check wether this frontend + * is currently running or connect to the started() signal. + * * @see ctkCmdLineModuleFuture */ virtual ctkCmdLineModuleFuture future() const; @@ -172,6 +177,16 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject void resetValues(); +Q_SIGNALS: + + /** + * @brief This signal is emitted when the frontend is run. + * + * You can use this signal to get the ctkCmdLineModuleFuture instance + * from future() to interact with the running frontend. + */ + void started(); + protected: /** diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp new file mode 100644 index 0000000000..337e4f9669 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.cpp @@ -0,0 +1,57 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFuture.h" + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFuture::ctkCmdLineModuleFuture() +{ +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFuture::ctkCmdLineModuleFuture(ctkCmdLineModuleFutureInterface* p) + : QFuture<ctkCmdLineModuleResult>(p) +{ +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFuture::readAllOutputData() const +{ + return d.outputData(); +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFuture::readAllErrorData() const +{ + return d.errorData(); +} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleFuture::canCancel() const +{ + return d.canCancel(); +} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleFuture::canPause() const +{ + return d.canPause(); +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h index b49852717b..65cab95b1b 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h @@ -22,6 +22,8 @@ #ifndef CTKCMDLINEMODULEFUTURE_H #define CTKCMDLINEMODULEFUTURE_H +#include "ctkCommandLineModulesCoreExport.h" + #include "ctkCmdLineModuleFutureInterface.h" #include <QFuture> @@ -37,21 +39,19 @@ * - bool canCancel() * - bool canPause() */ -class ctkCmdLineModuleFuture : public QFuture<ctkCmdLineModuleResult> +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFuture : public QFuture<ctkCmdLineModuleResult> { public: - ctkCmdLineModuleFuture() - { - } + ctkCmdLineModuleFuture(); + + explicit ctkCmdLineModuleFuture(ctkCmdLineModuleFutureInterface* p); // internal - explicit ctkCmdLineModuleFuture(ctkCmdLineModuleFutureInterface* p) // internal - : QFuture<ctkCmdLineModuleResult>(p) - { - } + QByteArray readAllOutputData() const; + QByteArray readAllErrorData() const; - bool canCancel() const { return d.canCancel(); } - bool canPause() const { return d.canPause(); } + bool canCancel() const; + bool canPause() const; }; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.cpp new file mode 100644 index 0000000000..81e829478e --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.cpp @@ -0,0 +1,201 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFutureInterface.h" +#include "ctkCmdLineModuleFutureInterface_p.h" + +const int ctkCmdLineModuleFutureCallOutEvent::TypeId = QEvent::registerEventType(); + +//---------------------------------------------------------------------------- +// ctkCmdLineModuleFutureInterfacePrivate + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFutureInterfacePrivate::ctkCmdLineModuleFutureInterfacePrivate(ctkCmdLineModuleFutureInterface* q) + : RefCount(1) + , CanCancel(false) + , CanPause(false) + , q(q) +{ +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleFutureInterfacePrivate::sendCallOut(const ctkCmdLineModuleFutureCallOutEvent &callOutEvent) +{ + if (OutputConnections.isEmpty()) + { + return; + } + + for (int i = 0; i < OutputConnections.count(); ++i) + { + OutputConnections.at(i)->postCmdLineModuleCallOutEvent(callOutEvent); + } +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleFutureInterfacePrivate::connectOutputInterface(ctkCmdLineModuleFutureCallOutInterface *iface) +{ + QMutexLocker locker(&Mutex); + + if (q->isStarted()) + { + if (!this->OutputData.isEmpty()) + { + iface->postCmdLineModuleCallOutEvent(ctkCmdLineModuleFutureCallOutEvent(ctkCmdLineModuleFutureCallOutEvent::OutputReady)); + } + if (!this->ErrorData.isEmpty()) + { + iface->postCmdLineModuleCallOutEvent(ctkCmdLineModuleFutureCallOutEvent(ctkCmdLineModuleFutureCallOutEvent::ErrorReady)); + } + } + + OutputConnections.append(iface); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleFutureInterfacePrivate::disconnectOutputInterface(ctkCmdLineModuleFutureCallOutInterface *iface) +{ + QMutexLocker lock(&Mutex); + const int index = OutputConnections.indexOf(iface); + if (index == -1) + return; + OutputConnections.removeAt(index); + + iface->cmdLineModuleCallOutInterfaceDisconnected(); +} + +//---------------------------------------------------------------------------- +// QFutureInterface<ctkCmdLineModuleResult> + +//---------------------------------------------------------------------------- +QFutureInterface<ctkCmdLineModuleResult>::QFutureInterface(State initialState) + : QFutureInterfaceBase(initialState) + , d(new ctkCmdLineModuleFutureInterfacePrivate(this)) +{ +} + +//---------------------------------------------------------------------------- +QFutureInterface<ctkCmdLineModuleResult>::QFutureInterface(const QFutureInterface& other) + : QFutureInterfaceBase(other) + , d(other.d) +{ + d->RefCount.ref(); +} + +//---------------------------------------------------------------------------- +QFutureInterface<ctkCmdLineModuleResult>::~QFutureInterface() +{ + if (referenceCountIsOne()) + resultStore().clear(); + + if (!d->RefCount.deref()) + { + delete d; + } +} + +//---------------------------------------------------------------------------- +QFutureInterface<ctkCmdLineModuleResult> QFutureInterface<ctkCmdLineModuleResult>::canceledResult() +{ + return QFutureInterface(State(Started | Finished | Canceled)); +} + +//---------------------------------------------------------------------------- +QFutureInterface<ctkCmdLineModuleResult>& +QFutureInterface<ctkCmdLineModuleResult>::operator=(const QFutureInterface& other) +{ + if (referenceCountIsOne()) + resultStore().clear(); + + QFutureInterfaceBase::operator=(other); + + other.d->RefCount.ref(); + if (!d->RefCount.deref()) + delete d; + d = other.d; + + // update the q pointer in the private implementation + d->q = this; + + return *this; +} + +//---------------------------------------------------------------------------- +bool QFutureInterface<ctkCmdLineModuleResult>::canCancel() const +{ + return d->CanCancel; +} + +//---------------------------------------------------------------------------- +void QFutureInterface<ctkCmdLineModuleResult>::setCanCancel(bool canCancel) +{ + d->CanCancel = canCancel; +} + +//---------------------------------------------------------------------------- +bool QFutureInterface<ctkCmdLineModuleResult>::canPause() const +{ + return d->CanPause; +} + +//---------------------------------------------------------------------------- +void QFutureInterface<ctkCmdLineModuleResult>::setCanPause(bool canPause) +{ + d->CanPause = canPause; +} + +//---------------------------------------------------------------------------- +void QFutureInterface<ctkCmdLineModuleResult>::reportOutputData(const QByteArray& outputData) +{ + QMutexLocker l(&d->Mutex); + + if (isCanceled() || isFinished()) return; + d->OutputData.append(outputData); + d->sendCallOut(ctkCmdLineModuleFutureCallOutEvent(ctkCmdLineModuleFutureCallOutEvent::OutputReady)); +} + +//---------------------------------------------------------------------------- +void QFutureInterface<ctkCmdLineModuleResult>::reportErrorData(const QByteArray& errorData) +{ + QMutexLocker l(&d->Mutex); + + if (isCanceled() || isFinished()) return; + d->ErrorData.append(errorData); + d->sendCallOut(ctkCmdLineModuleFutureCallOutEvent(ctkCmdLineModuleFutureCallOutEvent::ErrorReady)); +} + +//---------------------------------------------------------------------------- +QByteArray QFutureInterface<ctkCmdLineModuleResult>::outputData(int position, int size) const +{ + QMutexLocker l(&d->Mutex); + if (size < 0) size = d->OutputData.size(); + if (size > d->OutputData.size() - position) size = d->OutputData.size() - position; + return QByteArray(d->OutputData.data() + position, size); +} + +//---------------------------------------------------------------------------- +QByteArray QFutureInterface<ctkCmdLineModuleResult>::errorData(int position, int size) const +{ + QMutexLocker l(&d->Mutex); + if (size < 0) size = d->ErrorData.size(); + if (size > d->ErrorData.size() - position) size = d->ErrorData.size() - position; + return QByteArray(d->ErrorData.data() + position, size); +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h index e3603fa42b..55d96e5c19 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h @@ -22,76 +22,71 @@ #ifndef CTKCMDLINEMODULEFUTUREINTERFACE_H #define CTKCMDLINEMODULEFUTUREINTERFACE_H +#include <ctkCommandLineModulesCoreExport.h> + #include "ctkCmdLineModuleResult.h" #include <QFutureInterface> class ctkCmdLineModuleFuture; +class ctkCmdLineModuleFutureInterfacePrivate; /** - * \class ctkCmdLineModuleFutureInterface * \ingroup CommandLineModulesCore + * + * \brief A QFutureInterface specialization. + * + * This QFutureInterface must be used by custom backend implementations to retrieve + * a suitable QFuture object and to report state changes to it via this interface. */ template <> -class QFutureInterface<ctkCmdLineModuleResult> : public QFutureInterfaceBase +class CTK_CMDLINEMODULECORE_EXPORT QFutureInterface<ctkCmdLineModuleResult> : public QFutureInterfaceBase { public: - QFutureInterface(State initialState = NoState) - : QFutureInterfaceBase(initialState), - CanCancel(false), CanPause(false) - { } - - QFutureInterface(const QFutureInterface &other) - : QFutureInterfaceBase(other), - CanCancel(other.CanCancel), CanPause(other.CanPause) - { } - - ~QFutureInterface() - { - if (referenceCountIsOne()) - resultStore().clear(); - } - - static QFutureInterface canceledResult() - { return QFutureInterface(State(Started | Finished | Canceled)); } - - QFutureInterface& operator=(const QFutureInterface& other) - { - if (referenceCountIsOne()) - resultStore().clear(); - QFutureInterfaceBase::operator=(other); - CanCancel = other.CanCancel; - CanPause = other.CanPause; - return *this; - } + QFutureInterface(State initialState = NoState); + + QFutureInterface(const QFutureInterface &other); + + ~QFutureInterface(); + + static QFutureInterface canceledResult(); + + QFutureInterface& operator=(const QFutureInterface& other); inline ctkCmdLineModuleFuture future(); // implemented in ctkCmdLineModuleFuture.h - inline bool canCancel() const { return CanCancel; } - inline void setCanCancel(bool canCancel) { CanCancel = canCancel; } - inline bool canPause() const { return CanPause; } - inline void setCanPause(bool canPause) { CanPause = canPause; } + bool canCancel() const; + void setCanCancel(bool canCancel); + bool canPause() const; + void setCanPause(bool canPause); inline void reportResult(const ctkCmdLineModuleResult *result, int index = -1); inline void reportResult(const ctkCmdLineModuleResult &result, int index = -1); inline void reportResults(const QVector<ctkCmdLineModuleResult> &results, int beginIndex = -1, int count = -1); inline void reportFinished(const ctkCmdLineModuleResult *result = 0); + void reportOutputData(const QByteArray& outputData); + void reportErrorData(const QByteArray& errorData); + inline const ctkCmdLineModuleResult &resultReference(int index) const; inline const ctkCmdLineModuleResult *resultPointer(int index) const; inline QList<ctkCmdLineModuleResult> results(); + QByteArray outputData(int position = 0, int size = -1) const; + QByteArray errorData(int position = 0, int size = -1) const; + private: + friend class ctkCmdLineModuleFutureWatcherPrivate; + QtConcurrent::ResultStore<ctkCmdLineModuleResult> &resultStore() { return static_cast<QtConcurrent::ResultStore<ctkCmdLineModuleResult> &>(resultStoreBase()); } const QtConcurrent::ResultStore<ctkCmdLineModuleResult> &resultStore() const { return static_cast<const QtConcurrent::ResultStore<ctkCmdLineModuleResult> &>(resultStoreBase()); } - bool CanCancel; - bool CanPause; + ctkCmdLineModuleFutureInterfacePrivate* d; }; inline void QFutureInterface<ctkCmdLineModuleResult>::reportResult(const ctkCmdLineModuleResult *result, int index) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface_p.h new file mode 100644 index 0000000000..ad3cf37250 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface_p.h @@ -0,0 +1,90 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFUTUREINTERFACE_P_H +#define CTKCMDLINEMODULEFUTUREINTERFACE_P_H + +#include <QEvent> +#include <QAtomicInt> +#include <QMutex> + +class ctkCmdLineModuleFutureCallOutEvent : public QEvent +{ +public: + + static const int TypeId; + + enum CallOutType { + OutputReady, + ErrorReady + }; + + ctkCmdLineModuleFutureCallOutEvent() + : QEvent(static_cast<QEvent::Type>(TypeId)) + , callOutType(CallOutType(0)) + {} + + ctkCmdLineModuleFutureCallOutEvent(CallOutType callOutType) + : QEvent(static_cast<QEvent::Type>(TypeId)) + , callOutType(callOutType) + {} + + ctkCmdLineModuleFutureCallOutEvent* clone() const + { + return new ctkCmdLineModuleFutureCallOutEvent(callOutType); + } + + CallOutType callOutType; +}; + +class ctkCmdLineModuleFutureCallOutInterface +{ +public: + virtual ~ctkCmdLineModuleFutureCallOutInterface() {} + virtual void postCmdLineModuleCallOutEvent(const ctkCmdLineModuleFutureCallOutEvent &) = 0; + virtual void cmdLineModuleCallOutInterfaceDisconnected() = 0; +}; + +class ctkCmdLineModuleFutureInterfacePrivate +{ +public: + + ctkCmdLineModuleFutureInterfacePrivate(ctkCmdLineModuleFutureInterface* q); + + QAtomicInt RefCount; + mutable QMutex Mutex; + + QList<ctkCmdLineModuleFutureCallOutInterface *> OutputConnections; + + bool CanCancel; + bool CanPause; + + QByteArray OutputData; + QByteArray ErrorData; + + ctkCmdLineModuleFutureInterface* q; + + void sendCallOut(const ctkCmdLineModuleFutureCallOutEvent &callOut); + void connectOutputInterface(ctkCmdLineModuleFutureCallOutInterface *iface); + void disconnectOutputInterface(ctkCmdLineModuleFutureCallOutInterface *iface); +}; + +#endif // CTKCMDLINEMODULEFUTUREINTERFACE_P_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp new file mode 100644 index 0000000000..8a932827c1 --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp @@ -0,0 +1,216 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleFutureWatcher.h" + +#include "ctkCmdLineModuleFuture.h" +#include "ctkCmdLineModuleFutureInterface_p.h" + +#include <QThread> +#include <QCoreApplication> + +//---------------------------------------------------------------------------- +struct ctkCmdLineModuleFutureWatcherPrivate : public ctkCmdLineModuleFutureCallOutInterface +{ + ctkCmdLineModuleFutureWatcherPrivate(ctkCmdLineModuleFutureWatcher* q) + : q(q) + , pendingOutputReadyEvent(NULL) + , pendingErrorReadyEvent(NULL) + , outputPos(0) + , errorPos(0) + {} + + void connectOutputInterface() + { + q->futureInterface().d->connectOutputInterface(this); + } + + void disconnectOutputInterface(bool pendingAssignment = false) + { + if (pendingAssignment) + { + delete this->pendingOutputReadyEvent; + this->pendingOutputReadyEvent = NULL; + delete this->pendingErrorReadyEvent; + this->pendingErrorReadyEvent = NULL; + } + + q->futureInterface().d->disconnectOutputInterface(this); + } + + void postCmdLineModuleCallOutEvent(const ctkCmdLineModuleFutureCallOutEvent& callOutEvent) + { + QCoreApplication::postEvent(q, callOutEvent.clone()); + } + + void cmdLineModuleCallOutInterfaceDisconnected() + { + QCoreApplication::removePostedEvents(q, ctkCmdLineModuleFutureCallOutEvent::TypeId); + } + + void sendCmdLineModuleCallOutEvent(ctkCmdLineModuleFutureCallOutEvent* event) + { + if (q->futureInterface().isCanceled()) return; + + switch (event->callOutType) + { + case ctkCmdLineModuleFutureCallOutEvent::OutputReady: + emit q->outputDataReady(); + break; + case ctkCmdLineModuleFutureCallOutEvent::ErrorReady: + emit q->errorDataReady(); + break; + default: break; + } + } + + ctkCmdLineModuleFutureWatcher* q; + + ctkCmdLineModuleFuture Future; + + ctkCmdLineModuleFutureCallOutEvent* pendingOutputReadyEvent; + ctkCmdLineModuleFutureCallOutEvent* pendingErrorReadyEvent; + int outputPos; + int errorPos; +}; + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFutureWatcher::ctkCmdLineModuleFutureWatcher(QObject* parent) + : QFutureWatcher(parent) + , d(new ctkCmdLineModuleFutureWatcherPrivate(this)) +{ +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFutureWatcher::~ctkCmdLineModuleFutureWatcher() +{ + disconnectOutputInterface(); +} + +//---------------------------------------------------------------------------- +void ctkCmdLineModuleFutureWatcher::setFuture(const ctkCmdLineModuleFuture& future) +{ + if (d->Future == future) return; + + d->outputPos = 0; + d->errorPos = 0; + + d->disconnectOutputInterface(true); + d->Future = future; + QFutureWatcher::setFuture(future); + d->connectOutputInterface(); +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFuture ctkCmdLineModuleFutureWatcher::future() const +{ + return d->Future; +} + +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleFutureWatcher::event(QEvent *event) +{ + if (event->type() == ctkCmdLineModuleFutureCallOutEvent::TypeId) + { + ctkCmdLineModuleFutureCallOutEvent* callOutEvent = static_cast<ctkCmdLineModuleFutureCallOutEvent*>(event); + + if (futureInterface().isPaused()) + { + if (callOutEvent->callOutType == ctkCmdLineModuleFutureCallOutEvent::OutputReady && + d->pendingOutputReadyEvent == NULL) + { + d->pendingOutputReadyEvent = callOutEvent->clone(); + } + if (callOutEvent->callOutType == ctkCmdLineModuleFutureCallOutEvent::ErrorReady && + d->pendingErrorReadyEvent == NULL) + { + d->pendingErrorReadyEvent = callOutEvent->clone(); + } + return true; + } + + d->sendCmdLineModuleCallOutEvent(callOutEvent); + return true; + } + else if (event->type() == QEvent::FutureCallOut) + { + bool result = QFutureWatcher::event(event); + + if (futureInterface().isRunning()) + { + // send all pending call outs + if (d->pendingOutputReadyEvent) + { + d->sendCmdLineModuleCallOutEvent(d->pendingOutputReadyEvent); + delete d->pendingOutputReadyEvent; + d->pendingOutputReadyEvent = NULL; + } + if (d->pendingErrorReadyEvent) + { + d->sendCmdLineModuleCallOutEvent(d->pendingErrorReadyEvent); + delete d->pendingErrorReadyEvent; + d->pendingErrorReadyEvent = NULL; + } + } + return result; + } + return QFutureWatcher::event(event); +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFutureWatcher::readPendingOutputData() const +{ + QByteArray output = futureInterface().outputData(d->outputPos); + d->outputPos += output.size(); + return output; +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFutureWatcher::readPendingErrorData() const +{ + QByteArray errorOutput = futureInterface().errorData(d->errorPos); + d->errorPos += errorOutput.size(); + return errorOutput; +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFutureWatcher::readAllOutputData() const +{ + return d->Future.readAllOutputData(); +} + +//---------------------------------------------------------------------------- +QByteArray ctkCmdLineModuleFutureWatcher::readAllErrorData() const +{ + return d->Future.readAllErrorData(); +} + +//---------------------------------------------------------------------------- +const ctkCmdLineModuleFutureInterface& ctkCmdLineModuleFutureWatcher::futureInterface() const +{ + return d->Future.d; +} + +//---------------------------------------------------------------------------- +ctkCmdLineModuleFutureInterface& ctkCmdLineModuleFutureWatcher::futureInterface() +{ + return d->Future.d; +} diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h new file mode 100644 index 0000000000..2330d1f84e --- /dev/null +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h @@ -0,0 +1,86 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEFUTUREWATCHER_H +#define CTKCMDLINEMODULEFUTUREWATCHER_H + +#include "ctkCommandLineModulesCoreExport.h" + +#include "ctkCmdLineModuleResult.h" +#include "ctkCmdLineModuleFutureInterface.h" + +#include <QFutureWatcher> + +class ctkCmdLineModuleFuture; +struct ctkCmdLineModuleFutureWatcherPrivate; + +/** + * @brief The ctkCmdLineModuleFutureWatcher class provides enhanced monitoring of a + * ctkCmdLineModuleFuture using signals and slots. + * + * This class enhances the standard QFutureWatcher class by adding the two signals + * outputDataReady() and errorDataReady(). These signals are fired whenver the watched + * future reports new output data (usually text written to the standard output channel) or + * new error data (usually text written to the standard error channel). + * + * Use readPendingOutputData() or readPendingErrorData() to get the newly added data. + */ +class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFutureWatcher : public QFutureWatcher<ctkCmdLineModuleResult> +{ + Q_OBJECT + +public: + + ctkCmdLineModuleFutureWatcher(QObject* parent = 0); + + ~ctkCmdLineModuleFutureWatcher(); + + void setFuture(const ctkCmdLineModuleFuture& future); + + ctkCmdLineModuleFuture future() const; + + bool event(QEvent* event); + + QByteArray readPendingOutputData() const; + QByteArray readPendingErrorData() const; + + QByteArray readAllOutputData() const; + QByteArray readAllErrorData() const; + +Q_SIGNALS: + + void outputDataReady(); + void errorDataReady(); + +private: + + friend class ctkCmdLineModuleFutureWatcherPrivate; + + QScopedPointer<ctkCmdLineModuleFutureWatcherPrivate> d; + + const ctkCmdLineModuleFutureInterface& futureInterface() const; + ctkCmdLineModuleFutureInterface& futureInterface(); + + // not imlemented + void setFuture(const QFuture<ctkCmdLineModuleResult>&); +}; + +#endif // CTKCMDLINEMODULEFUTUREWATCHER_H diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp index 39a76daabc..caad44d6f3 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleManager.cpp @@ -282,5 +282,6 @@ ctkCmdLineModuleFuture ctkCmdLineModuleManager::run(ctkCmdLineModuleFrontend *fr ctkCmdLineModuleFuture future = d->SchemeToBackend[frontend->location().scheme()]->run(frontend); frontend->setFuture(future); + emit frontend->started(); return future; } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index 0be65d2d09..25df86c07f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -22,6 +22,7 @@ #include "ctkCmdLineModuleXmlProgressWatcher.h" #include <QIODevice> +#include <QProcess> #include <QXmlStreamReader> #include <QDebug> @@ -42,7 +43,14 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate public: ctkCmdLineModuleXmlProgressWatcherPrivate(QIODevice* input, ctkCmdLineModuleXmlProgressWatcher* qq) - : input(input), readPos(0), q(qq), error(false), currentProgress(0) + : input(input), process(NULL), readPos(0), q(qq), error(false), currentProgress(0) + { + // wrap the content in an artifical root element + reader.addData("<module-root>"); + } + + ctkCmdLineModuleXmlProgressWatcherPrivate(QProcess* input, ctkCmdLineModuleXmlProgressWatcher* qq) + : input(input), process(input), readPos(0), q(qq), error(false), currentProgress(0) { // wrap the content in an artifical root element reader.addData("<module-root>"); @@ -56,9 +64,15 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate parseProgressXml(); } + void _q_readyReadError() + { + emit q->errorDataAvailable(process->readAllStandardError()); + } + void parseProgressXml() { QXmlStreamReader::TokenType type = reader.readNext(); + QByteArray outputData; while(type != QXmlStreamReader::Invalid) { switch(type) @@ -66,7 +80,14 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate case QXmlStreamReader::NoToken: break; case QXmlStreamReader::Characters: { - if (stack.empty()) break; + if (stack.empty()) + { + QByteArray output(reader.text().toAscii()); + // get rid of a possible newline after the last xml end tag + if (output.startsWith('\n')) output = output.remove(0,1); + outputData.append(output); + break; + } if (stack.size() == 2 && stack.front() == FILTER_START) { @@ -160,6 +181,10 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate .arg(reader.lineNumber()).arg(reader.columnNumber()) + reader.errorString()); } } + if (!outputData.isEmpty()) + { + emit q->outputDataAvailable(outputData); + } } void unexpectedNestedElement(const QString& element) @@ -173,6 +198,7 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate } QIODevice* input; + QProcess* process; qint64 readPos; ctkCmdLineModuleXmlProgressWatcher* q; bool error; @@ -197,6 +223,16 @@ ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QIODevice connect(d->input, SIGNAL(readyRead()), SLOT(_q_readyRead())); } +//---------------------------------------------------------------------------- +ctkCmdLineModuleXmlProgressWatcher::ctkCmdLineModuleXmlProgressWatcher(QProcess* input) + : d(new ctkCmdLineModuleXmlProgressWatcherPrivate(input, this)) +{ + if (d->input == NULL) return; + + connect(input, SIGNAL(readyReadStandardOutput()), SLOT(_q_readyRead())); + connect(input, SIGNAL(readyReadStandardError()), SLOT(_q_readyReadError())); +} + //---------------------------------------------------------------------------- ctkCmdLineModuleXmlProgressWatcher::~ctkCmdLineModuleXmlProgressWatcher() { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h index 547af834d7..85bc7f818f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h @@ -29,6 +29,7 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate; class QIODevice; +class QProcess; /** * \class ctkCmdLineModuleXmlProgressWatcher @@ -42,6 +43,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlProgressWatcher : public Q public: ctkCmdLineModuleXmlProgressWatcher(QIODevice* input); + ctkCmdLineModuleXmlProgressWatcher(QProcess* input); ~ctkCmdLineModuleXmlProgressWatcher(); Q_SIGNALS: @@ -51,11 +53,15 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlProgressWatcher : public Q void filterFinished(const QString& name); void filterXmlError(const QString& error); + void outputDataAvailable(const QByteArray& outputData); + void errorDataAvailable(const QByteArray& errorData); + private: friend class ctkCmdLineModuleXmlProgressWatcherPrivate; Q_PRIVATE_SLOT(d, void _q_readyRead()) + Q_PRIVATE_SLOT(d, void _q_readyReadError()) QScopedPointer<ctkCmdLineModuleXmlProgressWatcherPrivate> d; }; diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index 3e872c6ce7..6bc415a162 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -27,6 +27,7 @@ #include <ctkCmdLineModuleParameter.h> #include <ctkCmdLineModuleRunException.h> #include <ctkCmdLineModuleFuture.h> +#include <ctkCmdLineModuleFutureWatcher.h> #include "ctkCmdLineModuleSignalTester.h" @@ -85,6 +86,11 @@ class ctkCmdLineModuleFutureTester : public QObject { Q_OBJECT +public Q_SLOTS: + + void ouputDataReady(); + void errorDataReady(); + private Q_SLOTS: void initTestCase(); @@ -95,10 +101,16 @@ private Q_SLOTS: void testStartFinish(); void testProgress(); void testPauseAndCancel(); + void testOutput(); void testError(); private: + QByteArray outputData; + QByteArray errorData; + + ctkCmdLineModuleFutureWatcher* currentWatcher; + ctkCmdLineModuleFrontendMockupFactory factory; ctkCmdLineModuleBackendLocalProcess backend; @@ -108,6 +120,24 @@ private Q_SLOTS: ctkCmdLineModuleFrontend* frontend; }; +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::ouputDataReady() +{ + if (this->currentWatcher) + { + outputData.append(currentWatcher->readPendingOutputData()); + } +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::errorDataReady() +{ + if (this->currentWatcher) + { + errorData.append(currentWatcher->readPendingErrorData()); + } +} + //----------------------------------------------------------------------------- void ctkCmdLineModuleFutureTester::initTestCase() { @@ -120,6 +150,7 @@ void ctkCmdLineModuleFutureTester::initTestCase() //----------------------------------------------------------------------------- void ctkCmdLineModuleFutureTester::init() { + currentWatcher = 0; frontend = factory.create(moduleRef); } @@ -127,23 +158,26 @@ void ctkCmdLineModuleFutureTester::init() void ctkCmdLineModuleFutureTester::cleanup() { delete frontend; + outputData.clear(); + errorData.clear(); } //----------------------------------------------------------------------------- void ctkCmdLineModuleFutureTester::testStartFinish() { QList<QString> expectedSignals; - expectedSignals.push_back("module.started"); - expectedSignals.push_back("module.finished"); + expectedSignals << "module.started" + << "module.progressRangeChanged(0,0)" + << "module.progressValueChanged(0)" + << "module.progressRangeChanged(0,1000)" + << "module.errorReady" + << "module.progressValueChanged(1000)" + << "module.finished"; ctkCmdLineModuleSignalTester signalTester; - QFutureWatcher<ctkCmdLineModuleResult> watcher; - QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); - QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - ctkCmdLineModuleFuture future = manager.run(frontend); - watcher.setFuture(future); + signalTester.setFuture(future); future.waitForFinished(); QCoreApplication::processEvents(); @@ -154,35 +188,35 @@ void ctkCmdLineModuleFutureTester::testStartFinish() void ctkCmdLineModuleFutureTester::testProgress() { QList<QString> expectedSignals; - expectedSignals.push_back("module.started"); - // this signal is send when connecting a QFutureWatcher to - // an already started QFuture - expectedSignals.push_back("module.progressValueChanged"); - - // the following two signals are send when the module reports "filter start" - expectedSignals.push_back("module.progressValueChanged"); - expectedSignals.push_back("module.progressTextChanged"); - - // this signal is send when the module reports progress for "output1" - expectedSignals.push_back("module.progressValueChanged"); - - // the following two signal are sent at the end to report - // completion and the full standard output text. - expectedSignals.push_back("module.progressValueChanged"); - expectedSignals.push_back("module.progressTextChanged"); - expectedSignals.push_back("module.finished"); + expectedSignals << "module.started" + // the following signals are send when connecting a QFutureWatcher to + // an already started QFuture + << "module.progressRangeChanged(0,0)" + << "module.progressValueChanged(0)" + << "module.progressRangeChanged(0,1000)" - ctkCmdLineModuleSignalTester signalTester; + // the test module always reports error data when starting + << "module.errorReady" + + // the following two signals are send when the module reports "filter start" + << "module.progressValueChanged(1)" + << "module.progressTextChanged(Test Filter)" + + // this signal is send when the module reports progress for "output1" + << "module.progressValueChanged(999)" - QFutureWatcher<ctkCmdLineModuleResult> watcher; - QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); - QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &signalTester, SLOT(moduleProgressValueChanged(int))); - QObject::connect(&watcher, SIGNAL(progressTextChanged(QString)), &signalTester, SLOT(moduleProgressTextChanged(QString))); - QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); + // the output data (the order is not really deterministic here...) + << "module.outputReady" + + // the following signal is sent at the end to report completion + << "module.progressValueChanged(1000)" + << "module.finished"; + + ctkCmdLineModuleSignalTester signalTester; frontend->setValue("numOutputsVar", 1); ctkCmdLineModuleFuture future = manager.run(frontend); - watcher.setFuture(future); + signalTester.setFuture(future); future.waitForFinished(); @@ -197,19 +231,17 @@ void ctkCmdLineModuleFutureTester::testPauseAndCancel() { ctkCmdLineModuleSignalTester signalTester; - QFutureWatcher<ctkCmdLineModuleResult> watcher; - QObject::connect(&watcher, SIGNAL(started()), &signalTester, SLOT(moduleStarted())); - QObject::connect(&watcher, SIGNAL(paused()), &signalTester, SLOT(modulePaused())); - QObject::connect(&watcher, SIGNAL(resumed()), &signalTester, SLOT(moduleResumed())); - QObject::connect(&watcher, SIGNAL(canceled()), &signalTester, SLOT(moduleCanceled())); - QObject::connect(&watcher, SIGNAL(finished()), &signalTester, SLOT(moduleFinished())); - frontend->setValue("runtimeVar", 60); ctkCmdLineModuleFuture future = manager.run(frontend); - watcher.setFuture(future); + signalTester.setFuture(future); QList<QString> expectedSignals; - expectedSignals.push_back("module.started"); + expectedSignals << "module.started" + << "module.progressRangeChanged(0,0)" + << "module.progressValueChanged(0)" + << "module.progressRangeChanged(0,1000)" + << "module.errorReady"; + if (future.canPause()) { // Due to Qt bug 12152, these two signals are reversed @@ -253,6 +285,56 @@ void ctkCmdLineModuleFutureTester::testPauseAndCancel() QVERIFY(signalTester.checkSignals(expectedSignals)); } +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFutureTester::testOutput() +{ + ctkCmdLineModuleSignalTester signalTester; + + connect(signalTester.watcher(), SIGNAL(outputDataReady()), SLOT(ouputDataReady())); + connect(signalTester.watcher(), SIGNAL(errorDataReady()), SLOT(errorDataReady())); + + this->currentWatcher = signalTester.watcher(); + + frontend->setValue("numOutputsVar", 2); + frontend->setValue("errorTextVar", "Final error msg."); + ctkCmdLineModuleFuture future = manager.run(frontend); + signalTester.setFuture(future); + + future.waitForFinished(); + + // process pending events + QCoreApplication::processEvents(); + + QVERIFY(future.isFinished()); + + QList<QString> expectedSignals; + expectedSignals << "module.started" + << "module.progressRangeChanged(0,0)" + << "module.progressValueChanged(0)" + << "module.progressRangeChanged(0,1000)" + << "module.errorReady" + << "module.progressValueChanged(1)" + << "module.progressTextChanged(Test Filter)" + << "module.progressValueChanged(500)" + << "module.outputReady" + << "module.progressValueChanged(999)" + << "module.outputReady" + << "module.errorReady" + << "module.progressValueChanged(1000)" + << "module.finished"; + + QVERIFY(signalTester.checkSignals(expectedSignals)); + + const char* expectedOutput = "Output 1\nOutput 2\n"; + const char* expectedError = "A superficial error message.\nFinal error msg."; + + QCOMPARE(this->outputData.data(), expectedOutput); + QCOMPARE(this->errorData.data(), expectedError); + + QCOMPARE(future.readAllOutputData().data(), expectedOutput); + QCOMPARE(future.readAllErrorData().data(), expectedError); +} + //----------------------------------------------------------------------------- void ctkCmdLineModuleFutureTester::testError() { @@ -260,9 +342,7 @@ void ctkCmdLineModuleFutureTester::testError() frontend->setValue("exitCodeVar", 24); frontend->setValue("errorTextVar", "Some error occured\n"); - QFutureWatcher<ctkCmdLineModuleResult> watcher; ctkCmdLineModuleFuture future = manager.run(frontend); - watcher.setFuture(future); try { @@ -272,7 +352,7 @@ void ctkCmdLineModuleFutureTester::testError() catch (const ctkCmdLineModuleRunException& e) { QVERIFY2(e.errorCode() == 24, "Test matching error code"); - QVERIFY2(e.errorString() == "Some error occured\n", "Error text mismatch"); + QCOMPARE(future.readAllErrorData().data(), "A superficial error message.\nSome error occured\n"); } } diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp index c8addc1ea0..23508ecc87 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.cpp @@ -23,64 +23,109 @@ #include <QDebug> +ctkCmdLineModuleSignalTester::ctkCmdLineModuleSignalTester() +{ + connect(&Watcher, SIGNAL(started()), SLOT(moduleStarted())); + connect(&Watcher, SIGNAL(canceled()), SLOT(moduleCanceled())); + connect(&Watcher, SIGNAL(finished()), SLOT(moduleFinished())); + + connect(&Watcher, SIGNAL(paused()), SLOT(modulePaused())); + connect(&Watcher, SIGNAL(resumed()), SLOT(moduleResumed())); + + connect(&Watcher, SIGNAL(resultReadyAt(int)), SLOT(resultReadyAt(int))); + connect(&Watcher, SIGNAL(resultsReadyAt(int,int)), SLOT(resultReadyAt(int,int))); + + connect(&Watcher, SIGNAL(progressRangeChanged(int,int)), SLOT(progressRangeChanged(int,int))); + connect(&Watcher, SIGNAL(progressTextChanged(QString)), SLOT(progressTextChanged(QString))); + connect(&Watcher, SIGNAL(progressValueChanged(int)), SLOT(progressValueChanged(int))); + + connect(&Watcher, SIGNAL(outputDataReady()), SLOT(outputDataReady())); + connect(&Watcher, SIGNAL(errorDataReady()), SLOT(errorDataReady())); +} + +void ctkCmdLineModuleSignalTester::setFuture(const ctkCmdLineModuleFuture &future) +{ + this->Watcher.setFuture(future); +} + +ctkCmdLineModuleFutureWatcher *ctkCmdLineModuleSignalTester::watcher() +{ + return &this->Watcher; +} + void ctkCmdLineModuleSignalTester::moduleStarted() { - events.push_back("module.started"); + Events.push_back("module.started"); } void ctkCmdLineModuleSignalTester::moduleFinished() { - events.push_back("module.finished"); + Events.push_back("module.finished"); } -void ctkCmdLineModuleSignalTester::moduleProgressValueChanged(int /*progress*/) +void ctkCmdLineModuleSignalTester::moduleProgressValueChanged(int progress) { - events.push_back("module.progressValueChanged"); + Events.push_back(QString("module.progressValueChanged(%1)").arg(progress)); } -void ctkCmdLineModuleSignalTester::moduleProgressTextChanged(const QString &/*text*/) +void ctkCmdLineModuleSignalTester::moduleProgressTextChanged(const QString& text) { - events.push_back("module.progressTextChanged"); + Events.push_back(QString("module.progressTextChanged(\"%1\")").arg(text)); } void ctkCmdLineModuleSignalTester::modulePaused() { - events.push_back("module.paused"); + Events.push_back("module.paused"); } void ctkCmdLineModuleSignalTester::moduleResumed() { - events.push_back("module.resumed"); + Events.push_back("module.resumed"); } void ctkCmdLineModuleSignalTester::moduleCanceled() { - events.push_back("module.canceled"); + Events.push_back("module.canceled"); +} + +void ctkCmdLineModuleSignalTester::resultReadyAt(int resultIndex) +{ + Events.push_back(QString("module.resultReadyAt(%1)").arg(resultIndex)); +} + +void ctkCmdLineModuleSignalTester::resultReadyAt(int beginIndex, int endIndex) +{ + Events.push_back(QString("module.resultReadyAt(%1,%2)").arg(beginIndex).arg(endIndex)); +} + +void ctkCmdLineModuleSignalTester::progressRangeChanged(int minimum, int maximum) +{ + Events.push_back(QString("module.progressRangeChanged(%1,%2)").arg(minimum).arg(maximum)); } -void ctkCmdLineModuleSignalTester::filterStarted(const QString &/*name*/, const QString &/*comment*/) +void ctkCmdLineModuleSignalTester::progressValueChanged(int progressValue) { - events.push_back("filter.started"); + Events.push_back(QString("module.progressValueChanged(%1)").arg(progressValue)); } -void ctkCmdLineModuleSignalTester::filterProgress(float /*progress*/) +void ctkCmdLineModuleSignalTester::progressTextChanged(const QString &progressText) { - events.push_back("filter.progress"); + Events.push_back(QString("module.progressTextChanged(%1)").arg(progressText)); } -void ctkCmdLineModuleSignalTester::filterFinished(const QString &/*name*/) +void ctkCmdLineModuleSignalTester::outputDataReady() { - events.push_back("filter.finished"); + Events.push_back("module.outputReady"); } -void ctkCmdLineModuleSignalTester::filterXmlError(const QString &/*error*/) +void ctkCmdLineModuleSignalTester::errorDataReady() { - events.push_back("filter.xmlError"); + Events.push_back("module.errorReady"); } bool ctkCmdLineModuleSignalTester::checkSignals(const QList<QString>& expectedSignals) { - if (events.size() != expectedSignals.size()) + if (Events.size() != expectedSignals.size()) { dumpSignals(expectedSignals); return false; @@ -88,7 +133,7 @@ bool ctkCmdLineModuleSignalTester::checkSignals(const QList<QString>& expectedSi for (int i=0; i < expectedSignals.size(); ++i) { - if (expectedSignals[i] != events[i]) + if (expectedSignals[i] != Events[i]) { dumpSignals(expectedSignals); return false; @@ -99,11 +144,11 @@ bool ctkCmdLineModuleSignalTester::checkSignals(const QList<QString>& expectedSi void ctkCmdLineModuleSignalTester::dumpSignals(const QList<QString>& expectedSignals) { - int max = events.size() > expectedSignals.size() ? events.size() : expectedSignals.size(); + int max = Events.size() > expectedSignals.size() ? Events.size() : expectedSignals.size(); qDebug() << "Expected signal -- Actual signal"; for (int i = 0; i < max; ++i) { - QString sig = i < events.size() ? events[i] : QString(); + QString sig = i < Events.size() ? Events[i] : QString(); if (i < expectedSignals.size()) { qDebug() << " " << expectedSignals[i] << "--" << sig; diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h index eb3365c84c..2c3e8925f5 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleSignalTester.h @@ -22,15 +22,24 @@ #ifndef CTKCMDLINEMODULESIGNALTESTER_H #define CTKCMDLINEMODULESIGNALTESTER_H +#include "ctkCmdLineModuleFutureWatcher.h" + #include <QObject> #include <QList> +class ctkCmdLineModuleFuture; + class ctkCmdLineModuleSignalTester : public QObject { Q_OBJECT public: + ctkCmdLineModuleSignalTester(); + + void setFuture(const ctkCmdLineModuleFuture& future); + ctkCmdLineModuleFutureWatcher* watcher(); + bool checkSignals(const QList<QString>& expectedSignals); void dumpSignals(const QList<QString>& expectedSignals); @@ -46,14 +55,20 @@ public Q_SLOTS: virtual void moduleResumed(); virtual void moduleCanceled(); - virtual void filterStarted(const QString& name, const QString& comment); - virtual void filterProgress(float progress); - virtual void filterFinished(const QString& name); - virtual void filterXmlError(const QString& error); + virtual void resultReadyAt(int resultIndex); + virtual void resultReadyAt(int beginIndex, int endIndex); + + virtual void progressRangeChanged(int minimum, int maximum); + virtual void progressValueChanged(int progressValue); + virtual void progressTextChanged(const QString &progressText); + + virtual void outputDataReady(); + virtual void errorDataReady(); private: - QList<QString> events; + ctkCmdLineModuleFutureWatcher Watcher; + QList<QString> Events; }; #endif // CTKCMDLINEMODULESIGNALTESTER_H diff --git a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp index 5337896525..54872bc8eb 100644 --- a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp +++ b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp @@ -66,7 +66,7 @@ int main(int argc, char* argv[]) parser.addArgument("exitCode", "", QVariant::Int, "Exit code", 0); parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false); parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0); - parser.addArgument("errorText", "", QVariant::String, "Error text (will not be printed on exit code 0)"); + parser.addArgument("errorText", "", QVariant::String, "Error text printed at the end"); QTextStream out(stdout, QIODevice::WriteOnly); QTextStream err(stderr, QIODevice::WriteOnly); @@ -104,6 +104,12 @@ int main(int argc, char* argv[]) bool exitCrash = parsedArgs["exitCrash"].toBool(); QString errorText = parsedArgs["errorText"].toString(); + err << "A superficial error message.\n"; + err.flush(); + + // sleep 500ms to give the "errorReady" signal a chance + sleep_ms(500); + QStringList outputs; for (int i = 0; i < numOutputs; ++i) { @@ -158,15 +164,17 @@ int main(int argc, char* argv[]) } } - // sleep 1 second to avoid squashing the last progress event with the finished event - sleep_ms(1000); + // sleep 500ms to avoid squashing the last progress event with the finished event + sleep_ms(500); + + out.flush(); if (exitCrash) { int* crash = 0; *crash = 5; } - if (exitCode != 0 && !errorText.isEmpty()) + if (!errorText.isEmpty()) { err << errorText; } diff --git a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml index 08e0a4a5b7..efbe04e069 100644 --- a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml +++ b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.xml @@ -56,7 +56,7 @@ Configurable behaviour for testing purposes. <string> <name>errorTextVar</name> <longflag>errorText</longflag> - <description>Final error message (not displayed if the exit code is 0).</description> + <description>Final error message at the end.</description> <label>Error text</label> </string> </parameters> From b09af0bf81751df81ad01702c3ba9df8034d26ca Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Wed, 29 Aug 2012 14:47:50 +0200 Subject: [PATCH 149/247] Use ctkCmdLineModuleFutureWatcher output reporting in the explorer app. --- .../CMakeLists.txt | 2 + .../ctkCmdLineModuleExplorerMainWindow.cpp | 3 + .../ctkCmdLineModuleExplorerMainWindow.h | 1 + .../ctkCmdLineModuleExplorerMainWindow.ui | 33 +++++ .../ctkCmdLineModuleExplorerOutputText.cpp | 129 ++++++++++++++++++ .../ctkCmdLineModuleExplorerOutputText.h | 61 +++++++++ .../ctkCmdLineModuleExplorerTabList.cpp | 1 + .../ctkCmdLineModuleExplorerTabList.h | 1 + 8 files changed, 231 insertions(+) create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.cpp create mode 100644 Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.h diff --git a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt index 9d27c06086..a6842fa446 100644 --- a/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt +++ b/Applications/ctkCommandLineModuleExplorer/CMakeLists.txt @@ -11,6 +11,7 @@ set(KIT_SRCS ctkCmdLineModuleExplorerMainWindow.h ctkCmdLineModuleExplorerMainWindow.cpp ctkCmdLineModuleExplorerModulesSettings.cpp + ctkCmdLineModuleExplorerOutputText.cpp ctkCmdLineModuleExplorerProgressWidget.cpp ctkCmdLineModuleExplorerTabList.cpp ctkCmdLineModuleExplorerTreeWidget.cpp @@ -20,6 +21,7 @@ set(KIT_SRCS set(KIT_MOC_SRCS ctkCmdLineModuleExplorerMainWindow.h ctkCmdLineModuleExplorerModulesSettings.h + ctkCmdLineModuleExplorerOutputText.h ctkCmdLineModuleExplorerProgressWidget.h ctkCmdLineModuleExplorerTabList.h ctkCmdLineModuleExplorerTreeWidget.h diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index c2f6bb036e..a91c98598b 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -92,6 +92,7 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : connect(ui->modulesTreeWidget, SIGNAL(moduleFrontendCreated(ctkCmdLineModuleFrontend*)), tabList.data(), SLOT(addTab(ctkCmdLineModuleFrontend*))); // React to tab-changes connect(tabList.data(), SIGNAL(tabActivated(ctkCmdLineModuleFrontend*)), SLOT(moduleTabActivated(ctkCmdLineModuleFrontend*))); + connect(tabList.data(), SIGNAL(tabClosed(ctkCmdLineModuleFrontend*)), ui->outputText, SLOT(frontendRemoved(ctkCmdLineModuleFrontend*))); // Listen to future events for the currently active tab @@ -290,6 +291,7 @@ void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend ui->actionPause->setEnabled(false); ui->actionCancel->setEnabled(false); ui->actionReset->setEnabled(false); + ui->outputText->setActiveFrontend(NULL); currentFutureWatcher.setFuture(ctkCmdLineModuleFuture()); } else @@ -299,6 +301,7 @@ void ctkCLModuleExplorerMainWindow::moduleTabActivated(ctkCmdLineModuleFrontend ui->actionPause->setChecked(module->isPaused()); ui->actionCancel->setEnabled(module->future().canCancel() && module->isRunning()); ui->actionReset->setEnabled(true); + ui->outputText->setActiveFrontend(module); currentFutureWatcher.setFuture(module->future()); } } diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h index 87c213b125..6a20ce578e 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.h @@ -90,6 +90,7 @@ protected Q_SLOTS: QTimer pollPauseTimer; QFutureWatcher<ctkCmdLineModuleResult> currentFutureWatcher; + QHash<ctkCmdLineModuleFrontend*, QByteArray> frontendToOutputMap; ctkCmdLineModuleDirectoryWatcher directoryWatcher; diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui index 6a856007ba..b38bff0898 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.ui @@ -159,6 +159,34 @@ </layout> </widget> </widget> + <widget class="QDockWidget" name="dockWidget_3"> + <property name="features"> + <set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set> + </property> + <property name="allowedAreas"> + <set>Qt::BottomDockWidgetArea|Qt::RightDockWidgetArea|Qt::TopDockWidgetArea</set> + </property> + <property name="windowTitle"> + <string>Output</string> + </property> + <attribute name="dockWidgetArea"> + <number>8</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_3"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="ctkCmdLineModuleExplorerOutputText" name="outputText"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> <action name="actionRun"> <property name="icon"> <iconset resource="resources/ctkCmdLineModuleExplorer.qrc"> @@ -243,6 +271,11 @@ <extends>QTreeWidget</extends> <header>ctkCmdLineModuleExplorerTreeWidget.h</header> </customwidget> + <customwidget> + <class>ctkCmdLineModuleExplorerOutputText</class> + <extends>QTextEdit</extends> + <header>ctkCmdLineModuleExplorerOutputText.h</header> + </customwidget> </customwidgets> <resources> <include location="resources/ctkCmdLineModuleExplorer.qrc"/> diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.cpp new file mode 100644 index 0000000000..ee4c203bce --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.cpp @@ -0,0 +1,129 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleExplorerOutputText.h" + +#include "ctkCmdLineModuleFrontend.h" +#include "ctkCmdLineModuleFuture.h" +#include "ctkCmdLineModuleFutureWatcher.h" + +ctkCmdLineModuleExplorerOutputText::ctkCmdLineModuleExplorerOutputText(QWidget* parent) + : QTextEdit(parent) + , CurrentWatcher(NULL) + , CurrentFrontend(NULL) +{ +} + +ctkCmdLineModuleExplorerOutputText::~ctkCmdLineModuleExplorerOutputText() +{ + qDeleteAll(this->FrontendToWatcherMap); +} + +void ctkCmdLineModuleExplorerOutputText::setActiveFrontend(ctkCmdLineModuleFrontend* moduleFrontend) +{ + if (this->CurrentFrontend == moduleFrontend) return; + + if (this->CurrentFrontend) + { + if (this->CurrentWatcher) + { + this->CurrentWatcher->disconnect(); + } + this->CurrentFrontend->disconnect(); + + // save the current output text + this->FrontendToOutputMap[this->CurrentFrontend] = this->toHtml(); + this->clear(); + } + + this->CurrentFrontend = moduleFrontend; + if (moduleFrontend) + { + // restore previous content + this->setHtml(this->FrontendToOutputMap[moduleFrontend]); + QTextCursor endCursor = this->textCursor(); + endCursor.movePosition(QTextCursor::End); + this->setTextCursor(endCursor); + + this->CurrentWatcher = FrontendToWatcherMap[moduleFrontend]; + if (this->CurrentWatcher == NULL) + { + this->CurrentWatcher = new ctkCmdLineModuleFutureWatcher; + this->FrontendToWatcherMap[moduleFrontend] = this->CurrentWatcher; + } + + connect(this->CurrentFrontend, SIGNAL(started()), SLOT(frontendStarted())); + + connect(this->CurrentWatcher, SIGNAL(outputDataReady()), SLOT(outputDataReady())); + connect(this->CurrentWatcher, SIGNAL(errorDataReady()), SLOT(errorDataReady())); + + this->CurrentWatcher->setFuture(moduleFrontend->future()); + + // if the frontend is already finished get any output we have not yet fetched + if (moduleFrontend->future().isFinished()) + { + this->outputDataReady(); + this->errorDataReady(); + } + } + else + { + if (this->CurrentWatcher) + { + this->CurrentWatcher->disconnect(); + this->CurrentWatcher = NULL; + } + if (this->CurrentFrontend) + { + this->CurrentFrontend->disconnect(); + this->CurrentFrontend = NULL; + } + this->clear(); + } +} + +void ctkCmdLineModuleExplorerOutputText::frontendRemoved(ctkCmdLineModuleFrontend *frontend) +{ + delete this->FrontendToWatcherMap[frontend]; + this->FrontendToWatcherMap.remove(frontend); + this->FrontendToOutputMap.remove(frontend); +} + +void ctkCmdLineModuleExplorerOutputText::frontendStarted() +{ + this->clear(); + this->FrontendToOutputMap[this->CurrentFrontend].clear(); + this->CurrentWatcher->setFuture(this->CurrentFrontend->future()); +} + +void ctkCmdLineModuleExplorerOutputText::outputDataReady() +{ + QByteArray newOutput = this->CurrentWatcher->readPendingOutputData(); + this->setTextColor(QColor(Qt::black)); + this->insertPlainText(newOutput.data()); +} + +void ctkCmdLineModuleExplorerOutputText::errorDataReady() +{ + QByteArray newOutput = this->CurrentWatcher->readPendingErrorData(); + this->setTextColor(QColor(Qt::darkRed)); + this->insertPlainText(newOutput.data()); +} diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.h new file mode 100644 index 0000000000..120eb4c64f --- /dev/null +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerOutputText.h @@ -0,0 +1,61 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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 CTKCMDLINEMODULEEXPLOREROUTPUTTEXT_H +#define CTKCMDLINEMODULEEXPLOREROUTPUTTEXT_H + + +#include <QTextEdit> + +class ctkCmdLineModuleFrontend; +class ctkCmdLineModuleFutureWatcher; + +class ctkCmdLineModuleExplorerOutputText : public QTextEdit +{ + Q_OBJECT + +public: + + ctkCmdLineModuleExplorerOutputText(QWidget* parent = 0); + ~ctkCmdLineModuleExplorerOutputText(); + +public Q_SLOTS: + + void setActiveFrontend(ctkCmdLineModuleFrontend* frontend); + + void frontendRemoved(ctkCmdLineModuleFrontend* frontend); + +private Q_SLOTS: + + void frontendStarted(); + + void outputDataReady(); + void errorDataReady(); + +private: + + ctkCmdLineModuleFutureWatcher* CurrentWatcher; + ctkCmdLineModuleFrontend* CurrentFrontend; + QHash<ctkCmdLineModuleFrontend*,ctkCmdLineModuleFutureWatcher*> FrontendToWatcherMap; + QHash<ctkCmdLineModuleFrontend*,QString> FrontendToOutputMap; +}; + +#endif // CTKCMDLINEMODULEEXPLOREROUTPUTTEXT_H diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp index 2217671650..ddd2291a7e 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.cpp @@ -116,6 +116,7 @@ void ctkCmdLineModuleExplorerTabList::tabCloseRequested(int index) { this->TabIndexToFrontend.removeAt(index); this->TabWidget->removeTab(index); + emit this->tabClosed(frontend); delete frontend; } } diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h index 0c1f8b02c3..b14be45963 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerTabList.h @@ -51,6 +51,7 @@ class ctkCmdLineModuleExplorerTabList : public QObject Q_SLOT void addTab(ctkCmdLineModuleFrontend* frontend); Q_SIGNAL void tabActivated(ctkCmdLineModuleFrontend* module); + Q_SIGNAL void tabClosed(ctkCmdLineModuleFrontend* module); private: From f4adf756c907c4ed3d16b6f0e352b5b0dfd34bce Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 00:59:06 +0200 Subject: [PATCH 150/247] Fixed Visual Studio compiler warnings. --- Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h | 2 +- Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h index 55d96e5c19..39fe55c5fd 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureInterface.h @@ -79,7 +79,7 @@ class CTK_CMDLINEMODULECORE_EXPORT QFutureInterface<ctkCmdLineModuleResult> : pu private: - friend class ctkCmdLineModuleFutureWatcherPrivate; + friend struct ctkCmdLineModuleFutureWatcherPrivate; QtConcurrent::ResultStore<ctkCmdLineModuleResult> &resultStore() { return static_cast<QtConcurrent::ResultStore<ctkCmdLineModuleResult> &>(resultStoreBase()); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h index 2330d1f84e..aa4fc9574d 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h @@ -72,7 +72,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFutureWatcher : public QFutur private: - friend class ctkCmdLineModuleFutureWatcherPrivate; + friend struct ctkCmdLineModuleFutureWatcherPrivate; QScopedPointer<ctkCmdLineModuleFutureWatcherPrivate> d; From 1a4220fb41021033f75b56b84cee17afba39e441 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 00:59:56 +0200 Subject: [PATCH 151/247] On Windows, terminating a process might not succeed - use kill instead. --- .../Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp index 42900a2391..35c8bdf580 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessWatcher.cpp @@ -122,7 +122,7 @@ void ctkCmdLineModuleProcessWatcher::resumeProcess() //---------------------------------------------------------------------------- void ctkCmdLineModuleProcessWatcher::cancelProcess() { - process.terminate(); + process.kill(); } //---------------------------------------------------------------------------- From f543ed806d3a3fb099098ffa2799e30f6e1b1473 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 01:00:32 +0200 Subject: [PATCH 152/247] Do not use Qt 4.8 QStringRef::toAscii() method. --- .../Core/ctkCmdLineModuleXmlProgressWatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index 25df86c07f..39ec58a26d 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -82,7 +82,7 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate { if (stack.empty()) { - QByteArray output(reader.text().toAscii()); + QByteArray output(reader.text().toString().toAscii()); // get rid of a possible newline after the last xml end tag if (output.startsWith('\n')) output = output.remove(0,1); outputData.append(output); From 113268d8ee4dfe6a07358158262dedab8fc0e9e0 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 01:01:11 +0200 Subject: [PATCH 153/247] Avoid sending pause/resume signals if the future does not support it. --- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index 6bc415a162..49bdaa5081 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -257,23 +257,30 @@ void ctkCmdLineModuleFutureTester::testPauseAndCancel() QTest::qWait(100); - future.pause(); - QTest::qWait(100); - - QVERIFY(future.isRunning()); if (future.canPause()) { + future.pause(); + QTest::qWait(100); QVERIFY(future.isPaused()); } - future.togglePaused(); + QVERIFY(future.isRunning()); - QTest::qWait(100); + if (future.canPause()) + { + future.togglePaused(); + QTest::qWait(100); + } QVERIFY(!future.isPaused()); QVERIFY(future.isRunning()); - future.cancel(); + if (future.canCancel()) + { + // give event processing a chance before killing the process + QTest::qWait(200); + future.cancel(); + } future.waitForFinished(); // process pending events From 0f3eaf31c0eab9f1a3022dd83fc3418ae3479e43 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 01:01:45 +0200 Subject: [PATCH 154/247] Use QIODevice::Text when opening text devices for proper \n translations. --- .../Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp | 2 +- .../Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp index 178b9b9fe6..94d8bebacf 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp +++ b/Libs/CommandLineModules/Backend/LocalProcess/ctkCmdLineModuleProcessTask.cpp @@ -83,7 +83,7 @@ void ctkCmdLineModuleProcessTask::run() QObject::connect(&process, SIGNAL(finished(int)), &localLoop, SLOT(quit())); QObject::connect(&process, SIGNAL(error(QProcess::ProcessError)), &localLoop, SLOT(quit())); - process.start(d->Location, d->Args); + process.start(d->Location, d->Args, QIODevice::ReadOnly | QIODevice::Text); ctkCmdLineModuleProcessWatcher progressWatcher(process, d->Location, *this); Q_UNUSED(progressWatcher) diff --git a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp index 54872bc8eb..2c47a18f96 100644 --- a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp +++ b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp @@ -67,8 +67,8 @@ int main(int argc, char* argv[]) parser.addArgument("exitCrash", "", QVariant::Bool, "Force crash", false); parser.addArgument("exitTime", "", QVariant::Int, "Exit time", 0); parser.addArgument("errorText", "", QVariant::String, "Error text printed at the end"); - QTextStream out(stdout, QIODevice::WriteOnly); - QTextStream err(stderr, QIODevice::WriteOnly); + QTextStream out(stdout, QIODevice::WriteOnly | QIODevice::Text); + QTextStream err(stderr, QIODevice::WriteOnly | QIODevice::Text); // Parse the command line arguments bool ok = false; @@ -104,8 +104,7 @@ int main(int argc, char* argv[]) bool exitCrash = parsedArgs["exitCrash"].toBool(); QString errorText = parsedArgs["errorText"].toString(); - err << "A superficial error message.\n"; - err.flush(); + err << "A superficial error message." << endl; // sleep 500ms to give the "errorReady" signal a chance sleep_ms(500); @@ -158,7 +157,7 @@ int main(int argc, char* argv[]) // print the first output if (output != "dummy") { - out << output; endl(out); + out << output << endl; // report progress out << "<filter-progress>" << (i+1)*progressStep << "</filter-progress>\n"; } From 849fe19caca0f74f49868d5351596b66e2e9d047 Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Thu, 30 Aug 2012 06:47:11 +0100 Subject: [PATCH 155/247] Unit test ctkCmdLineModuleDefaultPathBuilderTest --- Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 9d51a8b184..7cf3818b9e 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -3,6 +3,7 @@ set(LIBRARY_NAME ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp ctkCmdLineModuleXmlProgressWatcherTest.cpp + ctkCmdLineModuleDefaultPathBuilderTest.cpp ) set(TestsToRun ${Tests}) @@ -35,5 +36,5 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) # # Add Tests # - SIMPLE_TEST(ctkCmdLineModuleXmlProgressWatcherTest) +SIMPLE_TEST(ctkCmdLineModuleDefaultPathBuilderTest ${CTK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) \ No newline at end of file From 4ebce5380395efee3d62f1965ce7d967c316cd82 Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Thu, 30 Aug 2012 07:22:26 +0100 Subject: [PATCH 156/247] Actually aded ctkCmdLineModuleDefaultPathBuilderTest.cpp --- ...ctkCmdLineModuleDefaultPathBuilderTest.cpp | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleDefaultPathBuilderTest.cpp diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleDefaultPathBuilderTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleDefaultPathBuilderTest.cpp new file mode 100644 index 0000000000..df67436695 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleDefaultPathBuilderTest.cpp @@ -0,0 +1,136 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) University College London + + 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. + +=========================================================================*/ + +// Qt includes +#include <QList> +#include <QString> +#include <QDir> +#include <QApplication> +#include <QProcessEnvironment> + +// CTK includes +#include "ctkTest.h" +#include "ctkCmdLineModuleDefaultPathBuilder.h" + +// Others +#include <iostream> + +/** + * \fn Basic tests for ctkCmdLineModuleDefaultPathBuilderTest. + */ +int ctkCmdLineModuleDefaultPathBuilderTest(int argc, char* argv[]) +{ + QApplication myApp(argc, argv); + + if (argc != 2) + { + qDebug() << "Usage: ctkCmdLineModuleDefaultPathBuilderTest directoryThatTheApplicationIsIn"; + } + QString runtimeDirectoryName = argv[1]; + QDir runtimeDirectory(runtimeDirectoryName); + + ctkCmdLineModuleDefaultPathBuilder builder; + + QStringList defaultList = builder.build(); + if (defaultList.size() != 0) + { + qDebug() << "The default list should be empty"; + return EXIT_FAILURE; + } + + builder.setLoadFromCurrentDir(true); + + QStringList result = builder.build(); + qDebug() << "1. Built:" << result; + + if (result.size() != 2) + { + qDebug() << "The flag setLoadFromCurrentDir enables scanning of the current working directory plus the subfolder cli-modules"; + return EXIT_FAILURE; + } + + builder.setLoadFromApplicationDir(true); + + result = builder.build(); + qDebug() << "2. Built:" << result; + + if (result.size() != 4) + { + qDebug() << "The flag setLoadFromApplicationDir enables scanning of the current installation directory plus the subfolder cli-modules"; + return EXIT_FAILURE; + } + + builder.setLoadFromCurrentDir(false); + + result = builder.build(); + qDebug() << "3. Built:" << result; + + if (!result.contains(runtimeDirectory.absolutePath())) + { + qDebug() << "Loading from the application diretory (where THIS application is located), should produce the same path as passed in via the command line argument ${CTK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}"; + } + + builder.setLoadFromHomeDir(true); + + result = builder.build(); + qDebug() << "4. Built:" << result; + + if (result.size() != 4) + { + qDebug() << "Should now be loading from applicationDir, applicationDir/cli-modules, homeDir, homeDir/cli-modules"; + return EXIT_FAILURE; + } + + builder.setLoadFromCtkModuleLoadPath(true); + + result = builder.build(); + qDebug() << "5. Built:" << result; + + // If the environment variable CTK_MODULE_LOAD_PATH exists, it should point to a valid directory. + // If it does not exist, then the list should not change. + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + qDebug() << "Environment is:" << env.toStringList(); + + if (env.contains("CTK_MODULE_LOAD_PATH")) + { + QDir loadDir(env.value("CTK_MODULE_LOAD_PATH")); + + qDebug() << "CTK_MODULE_LOAD_PATH does exist, and is set to:" << env.value("CTK_MODULE_LOAD_PATH") << ", and isExists() returns " << loadDir.exists(); + + if (loadDir.exists() && result.size() != 5) + { + qDebug() << "Environment variable CTK_MODULE_LOAD_PATH did exist and is valid, so there should be 5 entries"; + return EXIT_FAILURE; + } + else if (!loadDir.exists() && result.size() != 4) + { + qDebug() << "Environment variable CTK_MODULE_LOAD_PATH did exist but is invalid, so there should be 4 entries"; + return EXIT_FAILURE; + } + } + else if (result.size() != 4) + { + qDebug() << "Environment variable CTK_MODULE_LOAD_PATH did not exist, so there should still be 4 entries as previous test"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + From 097f525ed245f4f112ff2ca338f29cd686b241c1 Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Thu, 30 Aug 2012 07:23:07 +0100 Subject: [PATCH 157/247] Fix template parameter when refering to QFutureWatcher in ctkCmdLineModuleFutureWatcher --- .../Core/ctkCmdLineModuleFutureWatcher.cpp | 8 ++++---- .../Core/ctkCmdLineModuleFutureWatcher.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp index 8a932827c1..8d8b713233 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.cpp @@ -94,7 +94,7 @@ struct ctkCmdLineModuleFutureWatcherPrivate : public ctkCmdLineModuleFutureCallO //---------------------------------------------------------------------------- ctkCmdLineModuleFutureWatcher::ctkCmdLineModuleFutureWatcher(QObject* parent) - : QFutureWatcher(parent) + : QFutureWatcher<ctkCmdLineModuleResult>(parent) , d(new ctkCmdLineModuleFutureWatcherPrivate(this)) { } @@ -115,7 +115,7 @@ void ctkCmdLineModuleFutureWatcher::setFuture(const ctkCmdLineModuleFuture& futu d->disconnectOutputInterface(true); d->Future = future; - QFutureWatcher::setFuture(future); + QFutureWatcher<ctkCmdLineModuleResult>::setFuture(future); d->connectOutputInterface(); } @@ -152,7 +152,7 @@ bool ctkCmdLineModuleFutureWatcher::event(QEvent *event) } else if (event->type() == QEvent::FutureCallOut) { - bool result = QFutureWatcher::event(event); + bool result = QFutureWatcher<ctkCmdLineModuleResult>::event(event); if (futureInterface().isRunning()) { @@ -172,7 +172,7 @@ bool ctkCmdLineModuleFutureWatcher::event(QEvent *event) } return result; } - return QFutureWatcher::event(event); + return QFutureWatcher<ctkCmdLineModuleResult>::event(event); } //---------------------------------------------------------------------------- diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h index aa4fc9574d..cc7a4766eb 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFutureWatcher.h @@ -37,7 +37,7 @@ struct ctkCmdLineModuleFutureWatcherPrivate; * ctkCmdLineModuleFuture using signals and slots. * * This class enhances the standard QFutureWatcher class by adding the two signals - * outputDataReady() and errorDataReady(). These signals are fired whenver the watched + * outputDataReady() and errorDataReady(). These signals are fired whenever the watched * future reports new output data (usually text written to the standard output channel) or * new error data (usually text written to the standard error channel). * From e852abdf22626ac009ef5dc403a7fedc17b5eb9d Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Fri, 31 Aug 2012 06:53:48 +0100 Subject: [PATCH 158/247] New classes ctkCmdLineModuleQtComboBox and ctkCmdLineModuleQtUiLoader for Qt frontend --- .../QtGui/ctkCmdLineModuleQtComboBox.cpp | 55 +++++++++++++++++++ .../QtGui/ctkCmdLineModuleQtComboBox_p.h | 48 ++++++++++++++++ .../QtGui/ctkCmdLineModuleQtUiLoader.cpp | 55 +++++++++++++++++++ .../QtGui/ctkCmdLineModuleQtUiLoader.h | 54 ++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp create mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp new file mode 100644 index 0000000000..f23375659f --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp @@ -0,0 +1,55 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) University College London + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleQtComboBox_p.h" + +//----------------------------------------------------------------------------- +ctkCmdLineModuleQtComboBox::ctkCmdLineModuleQtComboBox(QWidget *parent) +: QComboBox(parent) +{ +} + + +//----------------------------------------------------------------------------- +ctkCmdLineModuleQtComboBox::~ctkCmdLineModuleQtComboBox() +{ +} + + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleQtComboBox::setCurrentEnumeration(const QString& text) +{ + int i = findText(text); + if (i == -1) + { + i = this->currentIndex(); + } + this->setCurrentIndex(i); +} + + +//----------------------------------------------------------------------------- +QString ctkCmdLineModuleQtComboBox::currentEnumeration()const +{ + return this->currentText(); +} + + + diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h new file mode 100644 index 0000000000..60eb106923 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h @@ -0,0 +1,48 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) University College London + + 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 + + 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 CTKCMDLINEMODULEQTCOMBOBOX_H +#define CTKCMDLINEMODULEQTCOMBOBOX_H + +#include <QComboBox> + +/** + * \class ctkCmdLineModuleQtComboBox + * \brief Private subclass of QComboBox, providing the currentEnumeration and setCurrentEnumeration methods. + * \author m.clarkson@ucl.ac.uk + * \ingroup CommandLineModulesFrontendQtGui + */ +class ctkCmdLineModuleQtComboBox : public QComboBox +{ + + Q_OBJECT + Q_PROPERTY(QString currentEnumeration READ currentEnumeration WRITE setCurrentEnumeration) + +public: + + ctkCmdLineModuleQtComboBox(QWidget* parent = 0); + virtual ~ctkCmdLineModuleQtComboBox(); + + void setCurrentEnumeration(const QString& text); + QString currentEnumeration() const; + +}; + +#endif // CTKCMDLINEMODULEQTCOMBOBOX_H diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp new file mode 100644 index 0000000000..969ad0d332 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp @@ -0,0 +1,55 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) University College London + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleQtUiLoader.h" +#include "ctkCmdLineModuleQtComboBox_p.h" + +//----------------------------------------------------------------------------- +ctkCmdLineModuleQtUiLoader::ctkCmdLineModuleQtUiLoader(QObject *parent) + : QUiLoader(parent) +{ + +} + + +//----------------------------------------------------------------------------- +ctkCmdLineModuleQtUiLoader::~ctkCmdLineModuleQtUiLoader() +{ + +} + + +//----------------------------------------------------------------------------- +QWidget* ctkCmdLineModuleQtUiLoader::createWidget(const QString& className, QWidget* parent, const QString& name) +{ + QWidget* widget = NULL; + + if (className == "QComboBox") + { + widget = new ctkCmdLineModuleQtComboBox(parent); + widget->setObjectName(name); + } + else + { + widget = QUiLoader::createWidget(className, parent, name); + } + + return widget; +} diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h new file mode 100644 index 0000000000..02c00c52e8 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h @@ -0,0 +1,54 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) University College London + + 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 + + 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 CTKCMDLINEMODULEQTUILOADER_H +#define CTKCMDLINEMODULEQTUILOADER_H + +#include <QUiLoader> +#include "ctkCommandLineModulesFrontendQtGuiExport.h" + +/** + * \class ctkCmdLineModuleQtUiLoader + * \brief Derived from QUiLoader to enable us to instantiate custom widgets at runtime, + * where this class provides ctkCmdLineModuleQtComboBox instead of QComboBox. + * \author m.clarkson@ucl.ac.uk + * \ingroup CommandLineModulesFrontendQtGui + */ +class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleQtUiLoader : public QUiLoader +{ + + Q_OBJECT + +public: + ctkCmdLineModuleQtUiLoader(QObject *parent=0); + virtual ~ctkCmdLineModuleQtUiLoader(); + + /** + * \brief If className is QComboBox, instantiates ctkCmdLineModuleQtGuiComboBox and + * otherwise delegates to base class. + * \see QUiLoader::createWidget() + */ + virtual QWidget* createWidget(const QString & className, QWidget * parent = 0, const QString & name = QString() ); + +private: + +}; // end class + +#endif // CTKCMDLINEMODULEQTUILOADER_H From b912b92b6c9db3802032b08caa5b326462c658de Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Fri, 31 Aug 2012 06:54:27 +0100 Subject: [PATCH 159/247] Add new classes ctkCmdLineModuleQtComboBox and ctkCmdLineModuleQtUiLoader to CMakeLists.txt --- Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt index cd06b54758..402258f063 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt @@ -16,6 +16,8 @@ set(KIT_export_directive "CTK_CMDLINEMODULEQTGUI_EXPORT") set(KIT_SRCS ctkCmdLineModuleFrontendFactoryQtGui.cpp ctkCmdLineModuleFrontendQtGui.cpp + ctkCmdLineModuleQtUiLoader.cpp + ctkCmdLineModuleQtComboBox.cpp ctkCmdLineModuleMenuFactoryQtGui.cpp ctkCmdLineModuleObjectTreeWalker_p.h ctkCmdLineModuleObjectTreeWalker.cpp @@ -23,6 +25,8 @@ set(KIT_SRCS # Headers that should run through moc set(KIT_MOC_SRCS + ctkCmdLineModuleQtComboBox_p.h + ctkCmdLineModuleQtUiLoader.h ) # UI files From a8bd48ec2506bd8b30a4d9a3521fa8e63a2430b2 Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Fri, 31 Aug 2012 06:55:25 +0100 Subject: [PATCH 160/247] Set combo box to use property currentEnumeration --- .../Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index 86af278baf..dab961a683 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -38,7 +38,7 @@ <xsl:when test="$cliType= ('point', 'region')">coordinates</xsl:when> <xsl:when test="$cliType= ('image', 'file', 'directory', 'geometry')">currentPath</xsl:when> <xsl:when test="$cliType= ('string', 'integer-vector', 'float-vector', 'double-vector', 'string-vector')">text</xsl:when> - <xsl:when test="$cliType= ('integer-enumeration', 'float-enumeration', 'double-enumeration', 'string-enumeration')">currentText</xsl:when> + <xsl:when test="$cliType= ('integer-enumeration', 'float-enumeration', 'double-enumeration', 'string-enumeration')">currentEnumeration</xsl:when> <xsl:otherwise>value</xsl:otherwise> </xsl:choose> </xsl:function> From d24b327528b79a715a9eaef16064cbbf51b9703f Mon Sep 17 00:00:00 2001 From: MattClarkson <m.clarkson@ucl.ac.uk> Date: Fri, 31 Aug 2012 08:21:20 +0100 Subject: [PATCH 161/247] Removed ctkCmdLineModuleMenuFactoryQtGui as too application specific --- .../Frontend/QtGui/CMakeLists.txt | 1 - .../ctkCmdLineModuleMenuFactoryQtGui.cpp | 50 ------------------- .../QtGui/ctkCmdLineModuleMenuFactoryQtGui.h | 50 ------------------- 3 files changed, 101 deletions(-) delete mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp delete mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h diff --git a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt index 402258f063..2a10ba6b43 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt @@ -18,7 +18,6 @@ set(KIT_SRCS ctkCmdLineModuleFrontendQtGui.cpp ctkCmdLineModuleQtUiLoader.cpp ctkCmdLineModuleQtComboBox.cpp - ctkCmdLineModuleMenuFactoryQtGui.cpp ctkCmdLineModuleObjectTreeWalker_p.h ctkCmdLineModuleObjectTreeWalker.cpp ) diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp deleted file mode 100644 index 4bcd25ff7f..0000000000 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) University College London - - 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 - - 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. - -=============================================================================*/ - -#include "ctkCmdLineModuleMenuFactoryQtGui.h" -#include "ctkCmdLineModuleDescription.h" -#include <QList> -#include <QAction> - -//----------------------------------------------------------------------------- -ctkCmdLineModuleMenuFactoryQtGui::ctkCmdLineModuleMenuFactoryQtGui() -{ - -} - - -//----------------------------------------------------------------------------- -ctkCmdLineModuleMenuFactoryQtGui::~ctkCmdLineModuleMenuFactoryQtGui() -{ - -} - -//----------------------------------------------------------------------------- -QMenu* ctkCmdLineModuleMenuFactoryQtGui::create(const QList<ctkCmdLineModuleReference>& references) -{ - QMenu *menu = new QMenu(); - ctkCmdLineModuleReference ref; - - foreach (ref, references) - { - menu->addAction(ref.description().title()); - } - return menu; -} diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h deleted file mode 100644 index 16e362f319..0000000000 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleMenuFactoryQtGui.h +++ /dev/null @@ -1,50 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) University College London - - 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 - - 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 CTKCMDLINEMODULEMENUFACTORYQTGUI_H -#define CTKCMDLINEMODULEMENUFACTORYQTGUI_H - -#include <QMenu> -#include <QList> -#include "ctkCmdLineModuleReference.h" -#include "ctkCommandLineModulesFrontendQtGuiExport.h" - -/** - * \class ctkCmdLineModuleMenuFactoryQtGui - * \brief Takes a QHash of filename and ctkCmdLineModuleReference and produces a QMenu. - * \author m.clarkson@ucl.ac.uk - * \ingroup CommandLineModulesFrontendQtGui - */ -class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleMenuFactoryQtGui -{ -public: - - ctkCmdLineModuleMenuFactoryQtGui(); - virtual ~ctkCmdLineModuleMenuFactoryQtGui(); - - /** - * \brief Constructs a menu, for all the items in the QHash. - * \param list List of references, from which to build a menu. - * \return QMenu* a menu. - */ - QMenu* create(const QList<ctkCmdLineModuleReference>& list); -}; - -#endif // CTKCMDLINEMODULEMENUFACTORYQTGUI_H From 0cec71997dcb2a8db01c4d66455c9e022f107a30 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Thu, 30 Aug 2012 12:45:28 +0200 Subject: [PATCH 162/247] Clean up ctkCmdLineModuleParameter and friends. --- .../Core/ctkCmdLineModuleDescription.h | 4 +- .../Core/ctkCmdLineModuleParameter.cpp | 50 +------ .../Core/ctkCmdLineModuleParameter.h | 130 +++++++++++++++--- .../Core/ctkCmdLineModuleParameter_p.h | 5 - 4 files changed, 118 insertions(+), 71 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h index 7cab590b41..51c2d71559 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h @@ -40,8 +40,8 @@ class ctkCmdLineModuleParameter; * \ingroup CommandLineModulesCore * * The parameters can be used for automated GUI generation or execution - * of the module, and are directly related to the XML schema used to define - * a command line module. + * of the module, and are directly related to the XML description used to + * describe the command line module parameters. */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleDescription { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp index b216512ffb..2a78b31c9c 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp @@ -27,7 +27,7 @@ limitations under the License. //---------------------------------------------------------------------------- ctkCmdLineModuleParameterPrivate::ctkCmdLineModuleParameterPrivate() - : Hidden(false), Constraints(false), Index(-1), Multiple(false), Aggregate("false") + : Hidden(false), Constraints(false), Index(-1), Multiple(false) {} //---------------------------------------------------------------------------- @@ -81,25 +81,12 @@ QString ctkCmdLineModuleParameter::tag() const return d->Tag; } -////---------------------------------------------------------------------------- -//QString ctkCmdLineModuleParameter::cppType() const -//{ -// Q_D(const ctkCmdLineModuleParameter); -// return d->CPPType; -//} - //---------------------------------------------------------------------------- QString ctkCmdLineModuleParameter::type() const { return d->Type; } -//---------------------------------------------------------------------------- -QString ctkCmdLineModuleParameter::reference() const -{ - return d->Reference; -} - //---------------------------------------------------------------------------- bool ctkCmdLineModuleParameter::hidden() const { @@ -109,9 +96,8 @@ bool ctkCmdLineModuleParameter::hidden() const //---------------------------------------------------------------------------- bool ctkCmdLineModuleParameter::isReturnParameter() const { - // could check for tag == float, int, float-vector, ... - if (d->Channel == "output" - && !this->isFlagParameter() && !this->isIndexParameter()) + if (d->Channel == "output" && this->isIndexParameter() && + this->index() == 1000) { return true; } @@ -130,19 +116,6 @@ bool ctkCmdLineModuleParameter::isIndexParameter() const return (d->Index > -1); } -//---------------------------------------------------------------------------- -QString ctkCmdLineModuleParameter::argType() const -{ - return d->ArgType; -} - -////---------------------------------------------------------------------------- -//QString ctkCmdLineModuleParameter::stringToType() const -//{ -// Q_D(const ctkCmdLineModuleParameter); -// return d->StringToType; -//} - //---------------------------------------------------------------------------- QString ctkCmdLineModuleParameter::name() const { @@ -269,12 +242,6 @@ bool ctkCmdLineModuleParameter::multiple() const return d->Multiple; } -//---------------------------------------------------------------------------- -QString ctkCmdLineModuleParameter::aggregate() const -{ - return d->Aggregate; -} - //---------------------------------------------------------------------------- QString ctkCmdLineModuleParameter::fileExtensionsAsString() const { @@ -299,12 +266,6 @@ QStringList ctkCmdLineModuleParameter::elements() const return d->Elements; } -//---------------------------------------------------------------------------- -//QStringList& ctkCmdLineModuleParameter::elements() -//{ -// return d->Elements; -//} - //---------------------------------------------------------------------------- QTextStream& operator<<(QTextStream& os, const ctkCmdLineModuleParameter& parameter) { @@ -314,11 +275,7 @@ QTextStream& operator<<(QTextStream& os, const ctkCmdLineModuleParameter& parame os << " " << "Description: " << parameter.description() << '\n'; os << " " << "Label: " << parameter.label() << '\n'; os << " " << "Type: " << parameter.type() << '\n'; - os << " " << "Reference: " << parameter.reference() << '\n'; os << " " << "Hidden: " << (parameter.hidden() ? "true" : "false") << '\n'; - //os << " " << "CPPType: " << parameter.cppType() << '\n'; - os << " " << "ArgType: " << parameter.argType() << '\n'; - //os << " " << "StringToType: " << parameter.stringToType() << '\n'; os << " " << "Default: " << parameter.defaultValue() << '\n'; os << " " << "Elements: " << parameter.elements().join(", ") << '\n'; os << " " << "Constraints: " << (parameter.constraints() ? "true" : "false") << '\n'; @@ -334,7 +291,6 @@ QTextStream& operator<<(QTextStream& os, const ctkCmdLineModuleParameter& parame os << " " << "Channel: " << parameter.channel() << '\n'; os << " " << "Index: " << parameter.index() << '\n'; os << " " << "Multiple: " << (parameter.multiple() ? "true" : "false") << '\n'; - os << " " << "Aggregate: " << parameter.aggregate() << '\n'; os << " " << "FileExtensions: " << parameter.fileExtensionsAsString() << '\n'; os << " " << "CoordinateSystem: " << parameter.coordinateSystem() << '\n'; return os; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h index 49eccde1a9..5801218170 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h @@ -36,10 +36,10 @@ struct ctkCmdLineModuleParameterPrivate; * \ingroup CommandLineModulesCore * * - * ctkCmdLineModuleParameter describes a single parameters to a + * ctkCmdLineModuleParameter describes a single parameter for a * module. Information on the parameter type, name, flag, label, * description, channel, index, default, and constraints can be - * stored. + * retrieved. */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameter { @@ -51,76 +51,172 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameter ctkCmdLineModuleParameter& operator=(const ctkCmdLineModuleParameter& other); + /** + * @return The tag name, e.g. "integer" or "image". + */ QString tag() const; -// QString cppType() const; - + /** + * @return The type of the parameter, e.g. "scalar" or "vector" for image parameters. + */ QString type() const; - QString reference() const; - + /** + * @return <code>true</code> if the parameter is declared hidden, <code>false</code> + * otherwise. + */ bool hidden() const; - // Simple return types are parameters on output channel with no - // flags and without a specified index + /** + * Simple return types are parameters on the output channel with no + * flags and with a dummy index of 1000. + * + * @return <code>true</code> if the parameter is a simple return type, + * <code>false</code> otherwise. + */ bool isReturnParameter() const; - // Has a flag or a long flag? + /** + * @return <code>true</code> if the parameter has a flag (long or short), + * <code>false</code> otherwise. + */ bool isFlagParameter() const; - // Is an index type? + /** + * @return <code>true</code> if the parameter has an index, <code>false</code> otherwise. + */ bool isIndexParameter() const; - QString argType() const; - - //void setStringToType(const QString& stringToType); - //QString stringToType() const; - + /** + * @return The parameter name. + */ QString name() const; + /** + * @return The (possibly empty) long flag for this parameter. + */ QString longFlag() const; + /** + * @return A (possibly empty) comma separated string of aliases for the long flag. + */ QString longFlagAliasesAsString() const; + + /** + * @return A (possibly empty) list of long flag aliases. + */ QStringList longFlagAliases() const; + /** + * @return A (possibly empty) comma separated string of deprecated long flag aliases. + */ QString deprecatedLongFlagAliasesAsString() const; + + /** + * @return A (possibly empty) list of deprectated long flag aliases. + */ QStringList deprecatedLongFlagAliases() const; + /** + * @return The human-readable name of this parameter. + */ QString label() const; + /** + * @return <code>true</code> if this parameter imposes constraints on the set of allowed values. + */ bool constraints() const; + /** + * @return The maximum value constraint. + */ QString maximum() const; + /** + * @return The minimum value constraint. + */ QString minimum() const; + /** + * @return The value step size constraint. + */ QString step() const; + /** + * @return A longer description of this parameter. + */ QString description() const; + /** + * @return The string "input" for input parameters and "output" for output parameters. + */ QString channel() const; + /** + * @return The parameter index or <code>-1</code> if this is not an indexed parameter. + * @sa flag() + * @sa longFlag() + */ int index() const; + /** + * @return The default value. + */ QString defaultValue() const; + /** + * @return The (possibly empty) flag for this parameter. + * @sa index() + */ QString flag() const; + /** + * @return A (possibly empty) comma separated string of flag aliases. + */ QString flagAliasesAsString() const; + + /** + * @return A (possibly empty) list of flag aliases. + */ QStringList flagAliases() const; + /** + * @return A (possibly empty) comma separated string of deprecated flag aliases. + */ QString deprecatedFlagAliasesAsString() const; + + /** + * @return A (possibly empty) list of deprecated flag aliases. + */ QStringList deprecatedFlagAliases() const; + /** + * @return <code>true</code> if this parameter can appear multiple time in the argument list, + * <code>false</code> otherwise. + */ bool multiple() const; - QString aggregate() const; - + /** + * @return A (possibly empty) comma separated list of file extensions (e.g. "*.nrrd,*.mhd") for + * the "file", "image", or "geometry" parameter tags. + */ QString fileExtensionsAsString() const; + + /** + * @return A (possibly empty) list of file extensions. + * @sa fileExtensionsAsString() + */ QStringList fileExtensions() const; + /** + * @return The coordinate system (either "lps", "ras", oder "ijk") for the "point" or "region" + * parameter tags. + */ QString coordinateSystem() const; + /** + * @return The list of valid elements for enumeration parameters (e.g. "string-enumeration"). + */ QStringList elements() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h index a6cafd56fe..46b246ad96 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter_p.h @@ -39,12 +39,8 @@ struct ctkCmdLineModuleParameterPrivate : public QSharedData QString Name; QString Description; QString Label; - //QString CPPType; QString Type; - QString Reference; bool Hidden; - QString ArgType; - //QString StringToType; QString Default; QString Flag; QString LongFlag; @@ -55,7 +51,6 @@ struct ctkCmdLineModuleParameterPrivate : public QSharedData QString Channel; int Index; int Multiple; - QString Aggregate; QString FileExtensionsAsString; QStringList FileExtensions; QString CoordinateSystem; From 736e532a1de9467c1194667f5fdc63682ee3bce9 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 12:25:48 +0200 Subject: [PATCH 163/247] Output debug information when registering modules. --- .../ctkCmdLineModuleExplorerMainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp index a91c98598b..10e044e561 100644 --- a/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp +++ b/Applications/ctkCommandLineModuleExplorer/ctkCmdLineModuleExplorerMainWindow.cpp @@ -113,7 +113,7 @@ ctkCLModuleExplorerMainWindow::ctkCLModuleExplorerMainWindow(QWidget *parent) : // Register persistent modules QtConcurrent::mapped(settings.value(ctkCmdLineModuleExplorerConstants::KEY_REGISTERED_MODULES).toStringList(), - ctkCmdLineModuleConcurrentRegister(&moduleManager)); + ctkCmdLineModuleConcurrentRegister(&moduleManager, true)); // Start watching directories directoryWatcher.setDebug(true); From be16c9bd58c362b3838f1c5649630f46a57028e4 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 12:26:53 +0200 Subject: [PATCH 164/247] Extended QT4_GENERATE_MOCS macro and moved to main CMake folder. --- CMake/CTKConfig.cmake.in | 2 +- CMake/ctkMacroGenerateMocs.cmake | 21 +++++++++++++++++++ CMakeLists.txt | 1 + Libs/Testing/CMake/ctkMacroGenerateMocs.cmake | 11 ---------- Libs/Testing/CMakeLists.txt | 3 --- 5 files changed, 23 insertions(+), 15 deletions(-) create mode 100644 CMake/ctkMacroGenerateMocs.cmake delete mode 100644 Libs/Testing/CMake/ctkMacroGenerateMocs.cmake diff --git a/CMake/CTKConfig.cmake.in b/CMake/CTKConfig.cmake.in index 3c5171f038..1cbb3675d5 100644 --- a/CMake/CTKConfig.cmake.in +++ b/CMake/CTKConfig.cmake.in @@ -70,7 +70,7 @@ INCLUDE("@CTK_CMAKE_DIR_CONFIG@/ctkFunctionGetAllPluginTargets.cmake") INCLUDE("@CTK_CMAKE_DIR_CONFIG@/ctkFunctionGetTargetDependencies.cmake") INCLUDE("@CTK_CMAKE_DIR_CONFIG@/ctkFunctionGetPluginDependencies.cmake") INCLUDE("@CTK_CMAKE_DIR_CONFIG@/ctkMacroSetupPlugins.cmake") -INCLUDE("@CTKTesting_CMAKE_DIR_CONFIG@/ctkMacroGenerateMocs.cmake") +INCLUDE("@CTK_CMAKE_DIR_CONFIG@/ctkMacroGenerateMocs.cmake") SET(CTK_EXPORT_HEADER_TEMPLATE "@CTK_EXPORT_HEADER_TEMPLATE@") diff --git a/CMake/ctkMacroGenerateMocs.cmake b/CMake/ctkMacroGenerateMocs.cmake new file mode 100644 index 0000000000..3b73590b4c --- /dev/null +++ b/CMake/ctkMacroGenerateMocs.cmake @@ -0,0 +1,21 @@ + +# QT4_GENERATE_MOCS(inputfile1 [inputfile2 ...]) + +macro(QT4_GENERATE_MOCS) + foreach(file ${ARGN}) + set(moc_file moc_${file}) + QT4_GENERATE_MOC(${file} ${moc_file}) + + get_filename_component(source_name ${file} NAME_WE) + get_filename_component(source_ext ${file} EXT) + if(${source_ext} MATCHES "\\.[hH]") + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${source_name}.cpp) + set(source_ext .cpp) + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${source_name}.cxx) + set(source_ext .cxx) + endif() + endif() + set_property(SOURCE ${source_name}${source_ext} APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${moc_file}) + endforeach() +endmacro() + diff --git a/CMakeLists.txt b/CMakeLists.txt index 7af560434f..f6e3c06f88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,7 @@ include(CMake/ctkMacroBuildPlugin.cmake) include(CMake/ctkMacroBuildApp.cmake) include(CMake/ctkMacroBuildQtPlugin.cmake) include(CMake/ctkMacroCompilePythonScript.cmake) +include(CMake/ctkMacroGenerateMocs.cmake) include(CMake/ctkMacroWrapPythonQt.cmake) include(CMake/ctkMacroSetupQt.cmake) include(CMake/ctkMacroTargetLibraries.cmake) # Import multiple macros diff --git a/Libs/Testing/CMake/ctkMacroGenerateMocs.cmake b/Libs/Testing/CMake/ctkMacroGenerateMocs.cmake deleted file mode 100644 index fde7085195..0000000000 --- a/Libs/Testing/CMake/ctkMacroGenerateMocs.cmake +++ /dev/null @@ -1,11 +0,0 @@ - -# QT4_GENERATE_MOCS(inputfile1 [inputfile2 ...]) - -macro(QT4_GENERATE_MOCS) - foreach(file ${ARGN}) - set(moc_file moc_${file}) - QT4_GENERATE_MOC(${file} ${moc_file}) - macro_add_file_dependencies(${file} ${CMAKE_CURRENT_BINARY_DIR}/${moc_file}) - endforeach() -endmacro() - diff --git a/Libs/Testing/CMakeLists.txt b/Libs/Testing/CMakeLists.txt index c26d4bd0af..9cf6d82f6b 100644 --- a/Libs/Testing/CMakeLists.txt +++ b/Libs/Testing/CMakeLists.txt @@ -1,8 +1,5 @@ project(CTKTesting) -# CMake Macros -include(CMake/ctkMacroGenerateMocs.cmake) - if(CTK_USE_QTTESTING) include(../QtTesting/CMake/ctkQtTesting.cmake) endif() From 7edc0723527e98b4ed07eb3cc6569ca80fe89472 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 13:30:27 +0200 Subject: [PATCH 165/247] Hide the ctkCmdLineModuleQtComboBox impl in the custom UiLoader cpp file. --- .../Frontend/QtGui/CMakeLists.txt | 6 +- .../QtGui/ctkCmdLineModuleQtComboBox.cpp | 55 ------------------- .../QtGui/ctkCmdLineModuleQtComboBox_p.h | 48 ---------------- .../QtGui/ctkCmdLineModuleQtUiLoader.cpp | 44 +++++++++++++-- .../QtGui/ctkCmdLineModuleQtUiLoader.h | 1 - 5 files changed, 42 insertions(+), 112 deletions(-) delete mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp delete mode 100644 Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h diff --git a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt index 2a10ba6b43..642ad8f2ff 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtGui/CMakeLists.txt @@ -17,17 +17,19 @@ set(KIT_SRCS ctkCmdLineModuleFrontendFactoryQtGui.cpp ctkCmdLineModuleFrontendQtGui.cpp ctkCmdLineModuleQtUiLoader.cpp - ctkCmdLineModuleQtComboBox.cpp ctkCmdLineModuleObjectTreeWalker_p.h ctkCmdLineModuleObjectTreeWalker.cpp ) # Headers that should run through moc set(KIT_MOC_SRCS - ctkCmdLineModuleQtComboBox_p.h ctkCmdLineModuleQtUiLoader.h ) +qt4_generate_mocs( + ctkCmdLineModuleQtUiLoader.cpp +) + # UI files set(KIT_UI_FORMS ) diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp deleted file mode 100644 index f23375659f..0000000000 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) University College London - - 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 - - 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. - -=============================================================================*/ - -#include "ctkCmdLineModuleQtComboBox_p.h" - -//----------------------------------------------------------------------------- -ctkCmdLineModuleQtComboBox::ctkCmdLineModuleQtComboBox(QWidget *parent) -: QComboBox(parent) -{ -} - - -//----------------------------------------------------------------------------- -ctkCmdLineModuleQtComboBox::~ctkCmdLineModuleQtComboBox() -{ -} - - -//----------------------------------------------------------------------------- -void ctkCmdLineModuleQtComboBox::setCurrentEnumeration(const QString& text) -{ - int i = findText(text); - if (i == -1) - { - i = this->currentIndex(); - } - this->setCurrentIndex(i); -} - - -//----------------------------------------------------------------------------- -QString ctkCmdLineModuleQtComboBox::currentEnumeration()const -{ - return this->currentText(); -} - - - diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h deleted file mode 100644 index 60eb106923..0000000000 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtComboBox_p.h +++ /dev/null @@ -1,48 +0,0 @@ -/*============================================================================= - - Library: CTK - - Copyright (c) University College London - - 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 - - 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 CTKCMDLINEMODULEQTCOMBOBOX_H -#define CTKCMDLINEMODULEQTCOMBOBOX_H - -#include <QComboBox> - -/** - * \class ctkCmdLineModuleQtComboBox - * \brief Private subclass of QComboBox, providing the currentEnumeration and setCurrentEnumeration methods. - * \author m.clarkson@ucl.ac.uk - * \ingroup CommandLineModulesFrontendQtGui - */ -class ctkCmdLineModuleQtComboBox : public QComboBox -{ - - Q_OBJECT - Q_PROPERTY(QString currentEnumeration READ currentEnumeration WRITE setCurrentEnumeration) - -public: - - ctkCmdLineModuleQtComboBox(QWidget* parent = 0); - virtual ~ctkCmdLineModuleQtComboBox(); - - void setCurrentEnumeration(const QString& text); - QString currentEnumeration() const; - -}; - -#endif // CTKCMDLINEMODULEQTCOMBOBOX_H diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp index 969ad0d332..f3129a311f 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.cpp @@ -19,23 +19,53 @@ =============================================================================*/ #include "ctkCmdLineModuleQtUiLoader.h" -#include "ctkCmdLineModuleQtComboBox_p.h" + +#include <QComboBox> + //----------------------------------------------------------------------------- -ctkCmdLineModuleQtUiLoader::ctkCmdLineModuleQtUiLoader(QObject *parent) - : QUiLoader(parent) +/** + * \class ctkCmdLineModuleQtComboBox + * \brief Private subclass of QComboBox, providing the currentEnumeration and setCurrentEnumeration methods. + * \author m.clarkson@ucl.ac.uk + * \ingroup CommandLineModulesFrontendQtGui + */ +class ctkCmdLineModuleQtComboBox : public QComboBox { -} + Q_OBJECT + Q_PROPERTY(QString currentEnumeration READ currentEnumeration WRITE setCurrentEnumeration) +public: + + ctkCmdLineModuleQtComboBox(QWidget* parent = 0) + : QComboBox(parent) + {} + + void setCurrentEnumeration(const QString& text) + { + int i = findText(text); + if (i == -1) + { + return; + } + this->setCurrentIndex(i); + } + + QString currentEnumeration() const + { + return this->currentText(); + } + +}; //----------------------------------------------------------------------------- -ctkCmdLineModuleQtUiLoader::~ctkCmdLineModuleQtUiLoader() +ctkCmdLineModuleQtUiLoader::ctkCmdLineModuleQtUiLoader(QObject *parent) + : QUiLoader(parent) { } - //----------------------------------------------------------------------------- QWidget* ctkCmdLineModuleQtUiLoader::createWidget(const QString& className, QWidget* parent, const QString& name) { @@ -53,3 +83,5 @@ QWidget* ctkCmdLineModuleQtUiLoader::createWidget(const QString& className, QWid return widget; } + +#include "moc_ctkCmdLineModuleQtUiLoader.cpp" diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h index 02c00c52e8..18568f515b 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleQtUiLoader.h @@ -38,7 +38,6 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleQtUiLoader : public QUiLoade public: ctkCmdLineModuleQtUiLoader(QObject *parent=0); - virtual ~ctkCmdLineModuleQtUiLoader(); /** * \brief If className is QComboBox, instantiates ctkCmdLineModuleQtGuiComboBox and From b84835318728694b1e5491981e7ab1830f3527d1 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 13:31:11 +0200 Subject: [PATCH 166/247] Use ctkCmdLineModuleQtUiLoader by default in the frontend implementation. --- .../Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index 752f4d17fa..82b2ef01e8 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -24,6 +24,7 @@ #include "ctkCmdLineModuleReference.h" #include "ctkCmdLineModuleXslTransform.h" #include "ctkCmdLineModuleObjectTreeWalker_p.h" +#include "ctkCmdLineModuleQtUiLoader.h" #include <QBuffer> #include <QFile> @@ -69,7 +70,7 @@ QUiLoader* ctkCmdLineModuleFrontendQtGui::uiLoader() const { if (d->Loader == NULL) { - d->Loader.reset(new QUiLoader()); + d->Loader.reset(new ctkCmdLineModuleQtUiLoader()); } return d->Loader.data(); } From b7a2ba685eada74a48e8a5ea607e81bb712dd393 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 12:27:24 +0200 Subject: [PATCH 167/247] Added header so it shows up in IDEs. --- Libs/CommandLineModules/Core/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 922ea6137d..9bed047dc3 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -31,6 +31,7 @@ set(KIT_SRCS ctkCmdLineModuleFutureWatcher.cpp ctkCmdLineModuleManager.cpp ctkCmdLineModuleParameter.cpp + ctkCmdLineModuleParameter_p.h ctkCmdLineModuleParameterGroup.cpp ctkCmdLineModuleParameterGroup_p.h ctkCmdLineModuleParameterParsers_p.h From 32066e17cede4dc757162e37f585864cbf9009fb Mon Sep 17 00:00:00 2001 From: Sascha Zelzer <s.zelzer@dkfz-heidelberg.de> Date: Fri, 31 Aug 2012 12:39:52 +0200 Subject: [PATCH 168/247] Added additional "DisplayRole" enum and a role argument to setValue(). --- Libs/CommandLineModules/Core/CMakeLists.txt | 12 +- .../Core/ctkCmdLineModuleFrontend.h | 41 ++- .../Frontend/QtGui/Testing/Cpp/CMakeLists.txt | 9 +- .../Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp | 234 ++++++++++++++++++ ...kCmdLineModuleFrontendQtGuiTestModule1.xml | 36 +++ ...mdLineModuleFrontendQtGuiTestResources.qrc | 5 + .../QtGui/ctkCmdLineModuleFrontendQtGui.cpp | 39 ++- .../QtGui/ctkCmdLineModuleFrontendQtGui.h | 28 ++- .../ctkCmdLineModuleObjectTreeWalker.cpp | 13 +- .../ctkCmdLineModuleObjectTreeWalker_p.h | 2 +- .../ctkCmdLineModuleFrontendQtWebKit.cpp | 4 +- .../ctkCmdLineModuleFrontendQtWebKit_p.h | 2 +- .../Cpp/ctkCmdLineModuleFutureTest.cpp | 3 +- .../ctkCmdLineModuleQtCustomizationTest.cpp | 51 +++- 14 files changed, 442 insertions(+), 37 deletions(-) create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestModule1.xml create mode 100644 Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestResources.qrc diff --git a/Libs/CommandLineModules/Core/CMakeLists.txt b/Libs/CommandLineModules/Core/CMakeLists.txt index 9bed047dc3..5b4c76ecb9 100644 --- a/Libs/CommandLineModules/Core/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/CMakeLists.txt @@ -53,14 +53,18 @@ set(KIT_SRCS set(KIT_MOC_SRCS ctkCmdLineModuleDirectoryWatcher.h ctkCmdLineModuleDirectoryWatcher_p.h - ctkCmdLineModuleFrontend.h ctkCmdLineModuleFutureWatcher.h ctkCmdLineModuleManager.h ) -qt4_wrap_cpp(_dummy ctkCmdLineModuleXmlProgressWatcher.h) -set_source_files_properties(ctkCmdLineModuleXmlProgressWatcher.cpp - PROPERTIES OBJECT_DEPENDS ${_dummy}) +QT4_GENERATE_MOCS( + ctkCmdLineModuleFrontend.h + ctkCmdLineModuleXmlProgressWatcher.h +) + +#list(APPEND KIT_SRCS +# ${CMAKE_CURRENT_BINARY_DIR}/moc_ctkCmdLineModuleXmlProgressWatcher.h +#) # UI files set(KIT_UI_FORMS diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index ec7679bd91..a39d6ed051 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -45,6 +45,7 @@ struct ctkCmdLineModuleFrontendPrivate; class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject { Q_OBJECT + Q_ENUMS(ParamterValueRole) public: @@ -55,15 +56,28 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject * QVariant by default. For complex parameter types (like file, image, * geometry, etc.) the data must be convertible to a QString pointing * to a local resource. + * + * This role is usually used by backends for retrieving data and is mainly + * important for data which acts as a handle to the real data (e.g. a + * backend usually needs to get the absolute path to a local file for the + * current value of an input image parameter, instead of the image label + * displayed in a GUI). */ LocalResourceRole = 0, + /** + * Describes data suitable for displaying in a GUI. For many parameter types + * (e.g. scalar and vector parameters) data returned by this role will be + * the same as returned by the LocalResourceRole role. + **/ + DisplayRole = 1, + /** * This role can be used in custom frontends to return a QVariant * containing for example an in-memory representation of a complex object. * One can then either convert the in-memory representation to a local * resource before running a module such that arbitrary backends relying on - * the LocalResourceRole can process the data. Or one creates a custom + * the LocalResourceRole role can process the data. Or one creates a custom * backend which knows how to handle QVariants returned by this role. */ UserRole = 8 @@ -89,18 +103,24 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject /** * @brief GUIs will need to be able to read parameters, * here we retrieve by role. + * * @return QVariant * @see ParameterValueRole */ virtual QVariant value(const QString& parameter, - int role = LocalResourceRole) const = 0; + int role = LocalResourceRole) const = 0; /** - * @brief Set the value of a certain parameters + * @brief Set the value of a certain parameter. + * * @param parameter The name of the parameter, as defined in the XML. * @param value The value for that parameter. + * @param role The role for which to set the data. + * + * @see ParameterValueRole */ - virtual void setValue(const QString& parameter, const QVariant& value) = 0; + virtual void setValue(const QString& parameter, const QVariant& value, + int role = DisplayRole) = 0; /** * @brief Return the ctkCmdLineModuleFuture, derived from QFuture to @@ -159,8 +179,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject */ bool isPaused() const; - Q_SIGNAL void valueChanged(const QString& parameter, const QVariant& value); - // convenience methods /** @@ -179,6 +197,17 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject Q_SIGNALS: + /** + * @brief This signal is emitted whenever a parameter value is changed by using + * the ctkCmdLineModuleFrontent class. + * @param parameter The parameter name. + * @param value The new parameter value. + * + * Please note that this signal is not emitted if a parameter value is + * changed in the generated GUI. + */ + void valueChanged(const QString& parameter, const QVariant& value); + /** * @brief This signal is emitted when the frontend is run. * diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt index a6ca7d754b..708999cded 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/CMakeLists.txt @@ -2,6 +2,7 @@ set(KIT ${PROJECT_NAME}) set(LIBRARY_NAME ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp + ctkCmdLineModuleFrontendQtGuiTest.cpp ctkCmdLineModuleQtXslTransformTest.cpp ) @@ -9,10 +10,13 @@ set(TestsToRun ${Tests}) remove(TestsToRun ${KIT}CppTests.cpp) set(Tests_SRCS ${Tests_SRCS} - ) + set(Tests_MOC_SRCS ${Tests_MOC_SRCS} +) +set(Tests_RESOURCES + ctkCmdLineModuleFrontendQtGuiTestResources.qrc ) include_directories( @@ -23,6 +27,7 @@ include_directories( set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) QT4_GENERATE_MOCS( + ctkCmdLineModuleFrontendQtGuiTest.cpp ctkCmdLineModuleQtXslTransformTest.cpp ) set(Tests_UI_CPP) @@ -40,4 +45,4 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) # SIMPLE_TEST(ctkCmdLineModuleQtXslTransformTest) - +SIMPLE_TEST(ctkCmdLineModuleFrontendQtGuiTest) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp new file mode 100644 index 0000000000..895084a896 --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTest.cpp @@ -0,0 +1,234 @@ +/*========================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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. + +=========================================================================*/ + +// Qt includes +#include <QSpinBox> +#include <QComboBox> + +// CTK includes +#include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleBackend.h" +#include "ctkCmdLineModuleFrontendQtGui.h" +#include "ctkCmdLineModuleFuture.h" +#include "ctkCmdLineModuleDescription.h" +#include "ctkCmdLineModuleParameter.h" + +#include "ctkTest.h" + +namespace { + +class BackendMockUp : public ctkCmdLineModuleBackend +{ + +public: + + void addModule(const QUrl& location, const QByteArray& xml) + { + this->UrlToXml[location] = xml; + } + + virtual QString name() const { return "Mockup"; } + virtual QString description() const { return "Test Mock-up"; } + virtual QList<QString> schemes() const { return QList<QString>() << "test"; } + virtual qint64 timeStamp(const QUrl& /*location*/) const { return 0; } + virtual QByteArray rawXmlDescription(const QUrl& location) + { + return UrlToXml[location]; + } + +protected: + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* /*frontend*/) + { + return ctkCmdLineModuleFuture(); + } + +private: + + QHash<QUrl, QByteArray> UrlToXml; +}; + +} + +// ---------------------------------------------------------------------------- +class ctkCmdLineModuleFrontendQtGuiTester: public QObject +{ + Q_OBJECT + +private: + + QScopedPointer<ctkCmdLineModuleBackend> Backend; + ctkCmdLineModuleManager Manager; + + ctkCmdLineModuleReference ModuleRef; + + QString ChangedParameter; + QVariant ChangedParameterValue; + +private Q_SLOTS: + + void valueChanged(const QString& parameter, const QVariant& value); + +private Q_SLOTS: + + void initTestCase(); + + void init(); + + void testValueSetterAndGetter(); + void testValueSetterAndGetter_data(); + +}; + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGuiTester::valueChanged(const QString ¶meter, const QVariant &value) +{ + this->ChangedParameter = parameter; + this->ChangedParameterValue = value; +} + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGuiTester::initTestCase() +{ + BackendMockUp* backend = new BackendMockUp; + this->Backend.reset(backend); + + QFile xmlFile(":/ctkCmdLineModuleFrontendQtGuiTestModule1.xml"); + QVERIFY(xmlFile.open(QIODevice::ReadOnly)); + + backend->addModule(QUrl("test://module1"), xmlFile.readAll()); + + this->Manager.registerBackend(backend); + + this->ModuleRef = this->Manager.registerModule(QUrl("test://module1")); + QVERIFY(this->ModuleRef); +} + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGuiTester::init() +{ + this->ChangedParameter.clear(); + this->ChangedParameterValue.clear(); +} + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGuiTester::testValueSetterAndGetter() +{ + + QScopedPointer<ctkCmdLineModuleFrontend> frontend(new ctkCmdLineModuleFrontendQtGui(this->ModuleRef)); + // force the creation of the frontend gui + frontend->guiHandle(); + + connect(frontend.data(), SIGNAL(valueChanged(QString,QVariant)), SLOT(valueChanged(QString,QVariant))); + + QFETCH(QString, parameter); + QFETCH(QVariant, currentValue); + QFETCH(QVariant, newValue); + QFETCH(QVariant, expectedValue); + QFETCH(int, role); + + if (role == -1) + { + // test with default role argument + QCOMPARE(frontend->value(parameter), currentValue); + } + else + { + QCOMPARE(frontend->value(parameter, role), currentValue); + } + + // test setting values + if (newValue.isValid()) + { + frontend->setValue(parameter, newValue); + if (role == -1) + { + QCOMPARE(frontend->value(parameter), expectedValue); + } + else + { + QCOMPARE(frontend->value(parameter, role), expectedValue); + if (role == ctkCmdLineModuleFrontend::DisplayRole) + { + QWidget* widget = frontend->guiHandle()->findChild<QWidget*>("parameter:" + parameter); + QVERIFY(widget != NULL); + QString tag = this->ModuleRef.description().parameter(parameter).tag(); + if (tag == "integer") + { + QSpinBox* spinBox = qobject_cast<QSpinBox*>(widget); + QVERIFY(spinBox); + QCOMPARE(spinBox->value(), expectedValue.toInt()); + } + else if (tag.endsWith("enumeration")) + { + QComboBox* comboBox = qobject_cast<QComboBox*>(widget); + QVERIFY(comboBox); + QCOMPARE(comboBox->currentText(), expectedValue.toString()); + } + else + { + QFAIL("Missing widget sub-class test code."); + } + } + } + + QCOMPARE(this->ChangedParameter, parameter); + QCOMPARE(this->ChangedParameterValue, expectedValue); + } + +} + +// ---------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGuiTester::testValueSetterAndGetter_data() +{ + QTest::addColumn<QString>("parameter"); + QTest::addColumn<QVariant>("currentValue"); + QTest::addColumn<QVariant>("newValue"); + QTest::addColumn<QVariant>("expectedValue"); + QTest::addColumn<int>("role"); + + QTest::newRow("intParamDefaultDefaultRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << -1; + QTest::newRow("intParamDefaultDisplayRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole); + QTest::newRow("intParmaDefaultLRRole") << "intParam" << QVariant(1) << QVariant(2) << QVariant(2) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole); + + // newValue too low + QTest::newRow("intParamTooLowDefaultRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << -1; + QTest::newRow("intParamTooLowDisplayRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole); + QTest::newRow("intParmaTooLowLRRole") << "intParam" << QVariant(1) << QVariant(-6) << QVariant(-5) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole); + + // newValue too high + QTest::newRow("intParamTooHighDefaultRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << -1; + QTest::newRow("intParamTooHighDisplayRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole); + QTest::newRow("intParmaTooHighLRRole") << "intParam" << QVariant(1) << QVariant(200) << QVariant(60) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole); + + QTest::newRow("stringEnumDefaultRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << -1; + QTest::newRow("stringEnumDisplayRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole); + QTest::newRow("stringEnumLRRole") << "stringEnumParam" << QVariant("yes") << QVariant("no") << QVariant("no") << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole); + + QTest::newRow("intOutputParamDefaultRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << -1; + QTest::newRow("intOutputParamDisplayRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << static_cast<int>(ctkCmdLineModuleFrontend::DisplayRole); + QTest::newRow("intOutputParamLRRole") << "intOutputParam" << QVariant(0) << QVariant(3) << QVariant(3) << static_cast<int>(ctkCmdLineModuleFrontend::LocalResourceRole); +} + + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleFrontendQtGuiTest) +#include "moc_ctkCmdLineModuleFrontendQtGuiTest.cpp" diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestModule1.xml b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestModule1.xml new file mode 100644 index 0000000000..3d7885badf --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestModule1.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<executable> + <title>Test Module + Test Module. + + + Test parameters. + + intParam + i + Integer + + 1 + + -5 + 60 + 1 + + + + stringEnumParam + 0 + Enumeration parameter + + yes + no + + + intOutputParam + 1000 + Integer + + output + + +
diff --git a/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestResources.qrc b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestResources.qrc new file mode 100644 index 0000000000..19a40454fe --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/Testing/Cpp/ctkCmdLineModuleFrontendQtGuiTestResources.qrc @@ -0,0 +1,5 @@ + + + ctkCmdLineModuleFrontendQtGuiTestModule1.xml + + diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp index 82b2ef01e8..1994dbfc17 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.cpp @@ -105,6 +105,22 @@ QVariant ctkCmdLineModuleFrontendQtGui::customValue(const QString& parameter, co return QVariant(); } +//----------------------------------------------------------------------------- +void ctkCmdLineModuleFrontendQtGui::setCustomValue(const QString& parameter, const QVariant &value, + const QString& propertyName) +{ + if (!d->Widget) return; + + ctkCmdLineModuleObjectTreeWalker walker(d->Widget); + while(walker.readNextParameter()) + { + if(walker.name() == parameter && walker.value(propertyName) != value) + { + walker.setValue(value, propertyName); + break; + } + } +} //----------------------------------------------------------------------------- QObject* ctkCmdLineModuleFrontendQtGui::guiHandle() const @@ -146,23 +162,28 @@ QVariant ctkCmdLineModuleFrontendQtGui::value(const QString ¶meter, int role { Q_UNUSED(role) + // This will always return data using the default property for parameter values, + // which holds the data for the DisplayRole. return customValue(parameter); } //----------------------------------------------------------------------------- -void ctkCmdLineModuleFrontendQtGui::setValue(const QString ¶meter, const QVariant &value) +void ctkCmdLineModuleFrontendQtGui::setValue(const QString ¶meter, const QVariant &value, int role) { - if (!d->Widget) return; + if (role != DisplayRole) return; - ctkCmdLineModuleObjectTreeWalker walker(d->Widget); - while(walker.readNextParameter()) + QVariant oldValue = this->customValue(parameter); + + // This sets the value of the default QObject property for the DisplayRole. + this->setCustomValue(parameter, value); + + // Before emitting the signal, get the actual value because it might be different + // (Widgets with constraints on the value domain might adapt the value). + QVariant currentValue = this->customValue(parameter); + if (currentValue != oldValue) { - if(walker.name() == parameter && walker.value() != value) - { - walker.setValue(value); - emit valueChanged(parameter, value); - } + emit valueChanged(parameter, currentValue); } } diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index a9018d7f0d..67f41630a1 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -51,8 +51,33 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCm virtual QObject* guiHandle() const; + /** + * @brief Retrieves the current parameter value using the default QObject property for + * parameter values. + * @param parameter + * @param role + * + * This implementation ignores the role argument and always returns + * the value held by the default property, which usually correspongs to the + * DisplayRole. + * + * @see ctkCmdLineModuleFrontend::value() + */ virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const; - virtual void setValue(const QString& parameter, const QVariant& value); + + /** + * @brief Sets the parameter value. + * @param parameter + * @param value + * @param role + * + * This implementation does nothing if the role parameter does not equal + * ctkCmdLineModuleFrontend::DisplayRole. If it does, it sets the value of the default + * QObject property to the provided value. + * + * @see ctkCmdLiineModuleFrontend::setValue() + */ + virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole); virtual QList parameterNames() const; @@ -62,6 +87,7 @@ class CTK_CMDLINEMODULEQTGUI_EXPORT ctkCmdLineModuleFrontendQtGui : public ctkCm virtual ctkCmdLineModuleXslTransform* xslTransform() const; QVariant customValue(const QString& parameter, const QString& propertyName = QString()) const; + void setCustomValue(const QString& parameter, const QVariant& value, const QString& propertyName = QString()) ; private: diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp index 18244eeb17..64fdb8d690 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker.cpp @@ -116,12 +116,17 @@ QVariant ctkCmdLineModuleObjectTreeWalker::value(const QString &propertyName) co } //---------------------------------------------------------------------------- -void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value) +void ctkCmdLineModuleObjectTreeWalker::setValue(const QVariant& value, const QString &propertyName) { - QVariant valProp = property("valueProperty"); - if (valProp.isValid()) + QString valProp = propertyName; + if (valProp.isEmpty()) + { + valProp = property("valueProperty").toString(); + } + + if (!valProp.isEmpty()) { - CurrentObject->setProperty(qPrintable(valProp.toString()), value); + CurrentObject->setProperty(qPrintable(valProp), value); } } diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h index 7a7597c72f..0f2e0e7d0e 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleObjectTreeWalker_p.h @@ -60,7 +60,7 @@ class ctkCmdLineModuleObjectTreeWalker QString label() const; QVariant value(const QString& propertyName = QString()) const; - void setValue(const QVariant& value); + void setValue(const QVariant& value, const QString& propertyName = QString()); QString flag() const; QString longFlag() const; diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp index b4fa195af1..30c64dcf51 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit.cpp @@ -80,9 +80,9 @@ QVariant ctkCmdLineModuleFrontendQtWebKit::value(const QString ¶meter, int r } //---------------------------------------------------------------------------- -void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString ¶meter, const QVariant &value) +void ctkCmdLineModuleFrontendQtWebKit::setValue(const QString ¶meter, const QVariant &value, int role) { - if (!this->WebView) return; + if (!this->WebView || role != DisplayRole) return; QWebElement webElement = this->WebView->page()->currentFrame()->findFirstElement("input[name=" + parameter + "]"); if (webElement.isNull()) return; diff --git a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h index 0519b1aa57..066fa0b496 100644 --- a/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h +++ b/Libs/CommandLineModules/Frontend/QtWebKit/ctkCmdLineModuleFrontendQtWebKit_p.h @@ -43,7 +43,7 @@ class ctkCmdLineModuleFrontendQtWebKit : public ctkCmdLineModuleFrontend virtual QObject* guiHandle() const; virtual QVariant value(const QString& parameter, int role = LocalResourceRole) const; - virtual void setValue(const QString& parameter, const QVariant& value); + virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole); //virtual QList parameterNames() const; diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp index 49bdaa5081..3d6c829b2c 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleFutureTest.cpp @@ -64,8 +64,9 @@ class ctkCmdLineModuleFrontendMockupFactory : public ctkCmdLineModuleFrontendFac return value; } - virtual void setValue(const QString& parameter, const QVariant& value) + virtual void setValue(const QString& parameter, const QVariant& value, int role = DisplayRole) { + Q_UNUSED(role) currentValues[parameter] = value; } diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp index e3e71f89ed..8e62c1052f 100644 --- a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleQtCustomizationTest.cpp @@ -44,6 +44,7 @@ struct MyImageData : public ctk::CmdLineModuleBackendFunctionPointer::ImageType : Path(path) {} + QString Label; QString Path; }; @@ -69,7 +70,8 @@ class MyImageComboBox : public QComboBox public: - Q_PROPERTY(QString currentValue READ currentValue WRITE setCurrentValue) + Q_PROPERTY(QString currentLabel READ currentLabel WRITE setCurrentLabel) + Q_PROPERTY(QString currentPath READ currentPath WRITE setCurrentPath) Q_PROPERTY(const MyImageData* currentImage READ currentImage) MyImageComboBox(QWidget* parent = 0) @@ -84,12 +86,29 @@ class MyImageComboBox : public QComboBox this->addItem("Image 3"); } - QString currentValue() const + QString currentLabel() const + { + return this->imageData.at(this->currentIndex()).Label; + } + + void setCurrentLabel(const QString& label) + { + for(int i = 0; i < imageData.size(); ++i) + { + if (imageData[i].Label == label) + { + this->setCurrentIndex(i); + break; + } + } + } + + QString currentPath() const { return this->imageData.at(this->currentIndex()).Path; } - void setCurrentValue(const QString& path) + void setCurrentPath(const QString& path) { this->imageData[this->currentIndex()].Path = path; } @@ -143,6 +162,7 @@ class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui if (!initialized) { transform->bindVariable("imageInputWidget", "MyImageComboBox"); + transform->bindVariable("imageValueProperty", "currentLabel"); static QFile extraXsl(":/MyImageComboBoxTest.xsl"); transform->setXslExtraTransformation(&extraXsl); initialized = true; @@ -150,7 +170,7 @@ class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui return transform; } - QVariant value(const QString ¶meter, int role) const + QVariant value(const QString ¶meter, int role = LocalResourceRole) const { if (role == UserRole) { @@ -161,7 +181,26 @@ class MyQtGuiFrontend : public ctkCmdLineModuleFrontendQtGui } return QVariant(); } - return ctkCmdLineModuleFrontendQtGui::value(parameter, role); + else if (role == LocalResourceRole) + { + return this->customValue(parameter, "currentPath"); + } + else + { + return ctkCmdLineModuleFrontendQtGui::value(parameter, role); + } + } + + void setValue(const QString ¶meter, const QVariant &value, int role = DisplayRole) + { + if (role == LocalResourceRole) + { + this->setCustomValue(parameter, value, "currentPath"); + } + else + { + ctkCmdLineModuleFrontendQtGui::setValue(parameter, value, role); + } } }; @@ -235,7 +274,7 @@ void ctkCmdLineModuleQtCustomizationTester::testCustomization() // now set the property for the "LocalResourceRole" (the default property) to something else expectedImageValue = "/tmp/path/to/image2"; - fpFrontend->setValue("param0", expectedImageValue); + fpFrontend->setValue("param0", expectedImageValue, ctkCmdLineModuleFrontend::LocalResourceRole); QCOMPARE(fpFrontend->value("param0").toString(), expectedImageValue); QVERIFY(CustomImageDataPath.isEmpty()); From 5ea71602fa5dd03894aa6f1a080c05b23dea484b Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 31 Aug 2012 12:46:53 +0200 Subject: [PATCH 169/247] The "channel" element is now optionally allowed for all parameters. Previously, it was not possible to set the channel to "output" for simple parameter types. Now, channel is optional for all types and defaults to "input" (when parsing the XML description). Trying to do a "restriction" on the minOccurs attribute of the channel element in derived schema types turned out to be too complicated. --- .../Core/Resources/ctkCmdLineModule.xsd | 41 +++++++------------ .../Core/ctkCmdLineModuleParameter.cpp | 2 +- .../Core/ctkCmdLineModuleParameterParsers_p.h | 33 ++++----------- .../Core/ctkCmdLineModuleXmlParser.cpp | 2 +- .../Resources/ctkCmdLineModuleXmlToQtUi.xsl | 6 +++ 5 files changed, 30 insertions(+), 54 deletions(-) diff --git a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModule.xsd b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModule.xsd index e7105a9d32..aa7f066896 100644 --- a/Libs/CommandLineModules/Core/Resources/ctkCmdLineModule.xsd +++ b/Libs/CommandLineModules/Core/Resources/ctkCmdLineModule.xsd @@ -58,7 +58,7 @@ - + + + + + + + + + + @@ -216,29 +226,6 @@ - - - - - - - - - - - - - - - - - - - + @@ -282,7 +269,7 @@ diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp index 2a78b31c9c..0588ceca20 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.cpp @@ -27,7 +27,7 @@ limitations under the License. //---------------------------------------------------------------------------- ctkCmdLineModuleParameterPrivate::ctkCmdLineModuleParameterPrivate() - : Hidden(false), Constraints(false), Index(-1), Multiple(false) + : Hidden(false), Constraints(false), Channel("input"), Index(-1), Multiple(false) {} //---------------------------------------------------------------------------- diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h index 98c437ff6d..5585662b78 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterParsers_p.h @@ -115,6 +115,10 @@ struct ctkCmdLineModuleParameterParser { moduleParamPrivate->Index = xmlReader.readElementText().toInt(); } + else if (name.compare("channel", Qt::CaseInsensitive) == 0) + { + moduleParamPrivate->Channel = xmlReader.readElementText().trimmed(); + } else { xmlReader.skipCurrentElement(); @@ -237,35 +241,14 @@ class ctkCmdLineModulePointParameterParser : public ctkCmdLineModuleMultiplePara } }; -class ctkCmdLineModuleChannelParameterParser : public ctkCmdLineModuleMultipleParameterParser -{ - -protected: - - bool handleSubElement(ctkCmdLineModuleParameterPrivate* moduleParamPrivate, QXmlStreamReader& xmlReader) - { - QStringRef name = xmlReader.name(); - - if (name.compare("channel", Qt::CaseInsensitive) == 0) - { - moduleParamPrivate->Channel = xmlReader.readElementText().trimmed(); - return true; - } - else - { - return ctkCmdLineModuleMultipleParameterParser::handleSubElement(moduleParamPrivate, xmlReader); - } - } -}; - -class ctkCmdLineModuleFileParameterParser : public ctkCmdLineModuleChannelParameterParser +class ctkCmdLineModuleFileParameterParser : public ctkCmdLineModuleMultipleParameterParser { protected: void handleAttributes(ctkCmdLineModuleParameterPrivate* moduleParamPrivate, QXmlStreamReader& xmlReader) { - ctkCmdLineModuleChannelParameterParser::handleAttributes(moduleParamPrivate, xmlReader); + ctkCmdLineModuleMultipleParameterParser::handleAttributes(moduleParamPrivate, xmlReader); moduleParamPrivate->FileExtensionsAsString =xmlReader.attributes().value("fileExtensions").toString().trimmed(); } }; @@ -283,14 +266,14 @@ class ctkCmdLineModuleGeometryParameterParser : public ctkCmdLineModuleMultipleP } }; -class ctkCmdLineModuleImageParameterParser : public ctkCmdLineModuleChannelParameterParser +class ctkCmdLineModuleImageParameterParser : public ctkCmdLineModuleMultipleParameterParser { protected: void handleAttributes(ctkCmdLineModuleParameterPrivate* moduleParamPrivate, QXmlStreamReader& xmlReader) { - ctkCmdLineModuleChannelParameterParser::handleAttributes(moduleParamPrivate, xmlReader); + ctkCmdLineModuleMultipleParameterParser::handleAttributes(moduleParamPrivate, xmlReader); moduleParamPrivate->setFileExtensionsAsString(xmlReader.attributes().value("fileExtensions").toString().trimmed()); moduleParamPrivate->Type = xmlReader.attributes().value("type").toString().trimmed(); } diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp index eb0df1ddb2..b0b0ba61a8 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser.cpp @@ -67,7 +67,7 @@ ctkCmdLineModuleXmlParser::ctkCmdLineModuleXmlParser(QIODevice* device, _paramParsers["float-enumeration"] = new ctkCmdLineModuleEnumerationParameterParser; // type="enumerationType"/> _paramParsers["double-enumeration"] = new ctkCmdLineModuleEnumerationParameterParser; // type="enumerationType"/> _paramParsers["file"] = new ctkCmdLineModuleFileParameterParser; // type="fileType"/> - _paramParsers["directory"] = new ctkCmdLineModuleChannelParameterParser; // type="channelType"/> + _paramParsers["directory"] = new ctkCmdLineModuleMultipleParameterParser; // type="multipleType"/> _paramParsers["image"] = new ctkCmdLineModuleImageParameterParser; // type="imageType"/> _paramParsers["geometry"] = new ctkCmdLineModuleGeometryParameterParser; // type="geometryType"/> } diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index dab961a683..a4c89185b8 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -142,6 +142,12 @@ false + + + + false + + From b69f79033903bf0e2a5823e708e632b406c96156 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 31 Aug 2012 12:48:27 +0200 Subject: [PATCH 170/247] Removed obsolete property generation, added missing constraints template. --- .../Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index a4c89185b8..f7f99e1621 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -110,10 +110,6 @@ - - - - + From 45e79a8c7b9c59a0174210cabe9f5ab09c0bcefd Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 31 Aug 2012 12:49:52 +0200 Subject: [PATCH 171/247] Corrected order of signal emission for output data. --- .../Core/ctkCmdLineModuleXmlProgressWatcher.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index 39ec58a26d..08bb62b77f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -151,6 +151,11 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate if (parent.isEmpty()) { + if (!outputData.isEmpty()) + { + emit q->outputDataAvailable(outputData); + outputData.clear(); + } if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0) { emit q->filterStarted(currentName, currentComment); @@ -181,10 +186,6 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate .arg(reader.lineNumber()).arg(reader.columnNumber()) + reader.errorString()); } } - if (!outputData.isEmpty()) - { - emit q->outputDataAvailable(outputData); - } } void unexpectedNestedElement(const QString& element) From d4d211a517e2f40ff05253ee7e4be7c9b00b4a0b Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 31 Aug 2012 12:55:42 +0200 Subject: [PATCH 172/247] Moved default XSL parameter values to the XSL itself. --- .../Core/ctkCmdLineModuleXslTransform.cpp | 14 ----------- .../Resources/ctkCmdLineModuleXmlToQtUi.xsl | 23 ++++++++++++++++++- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp index 0fc37b503a..f4e4d4f18e 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp @@ -115,20 +115,6 @@ ctkCmdLineModuleXslTransform::ctkCmdLineModuleXslTransform(QIODevice *input, QIO : ctkCmdLineModuleXmlValidator(input) , d(new ctkCmdLineModuleXslTransformPrivate(output)) { - this->bindVariable("executableWidget", QVariant(QString("QWidget"))); - this->bindVariable("parametersWidget", QVariant(QString("ctkCollapsibleGroupBox"))); - this->bindVariable("booleanWidget", QVariant(QString("QCheckBox"))); - this->bindVariable("integerWidget", QVariant(QString("QSpinBox"))); - this->bindVariable("floatingWidget", QVariant(QString("QDoubleSpinBox"))); - this->bindVariable("vectorWidget", QVariant(QString("QLineEdit"))); - this->bindVariable("enumWidget", QVariant(QString("QComboBox"))); - this->bindVariable("imageInputWidget", QVariant(QString("ctkPathLineEdit"))); - this->bindVariable("imageOutputWidget", QVariant(QString("ctkPathLineEdit"))); - this->bindVariable("fileInputWidget", QVariant(QString("ctkPathLineEdit"))); - this->bindVariable("fileOutputWidget", QVariant(QString("ctkPathLineEdit"))); - this->bindVariable("directoryWidget", QVariant(QString("ctkPathLineEdit"))); - this->bindVariable("pointWidget", QVariant(QString("ctkCoordinatesWidget"))); - this->bindVariable("unsupportedWidget", QVariant(QString("QLabel"))); } //---------------------------------------------------------------------------- diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index f7f99e1621..8b34b27e7f 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -9,7 +9,28 @@ exclude-result-prefixes="xs xdt err fn"> - + + + + QWidget + ctkCollapsibleGroupBox + QCheckBox + QSpinBox + QDoubleSpinBox + QLineEdit + QComboBox + ctkPathLineEdit + ctkPathLineEdit + ctkPathLineEdit + ctkPathLineEdit + ctkPathLineEdit + ctkCoordinatesWidget + QLabel + + true + QWidget ctkCollapsibleGroupBox QCheckBox From 05dba05e90875f235a6dcdcf373637badccd01b7 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Fri, 31 Aug 2012 12:57:25 +0200 Subject: [PATCH 174/247] Made the property names for holding the DisplayRole data configurable. --- .../Resources/ctkCmdLineModuleXmlToQtUi.xsl | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index c2960e9388..b29279e310 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -32,6 +32,25 @@ ctkPathLineEdit ctkCoordinatesWidget QLabel + + checked + value + value + coordinates + coordinates + currentPath + currentPath + currentPath + currentPath + text + text + text + text + currentEnumeration + currentEnumeration + currentEnumeration + currentEnumeration + + + The root element for each module XML description. It must contain + at least one "parameters" element. + - - - - - - - - - + + + + Classifies the module (e.g. Filtering, Segmentation). + The value can be a dot separated string to create category hierarchies. + + + + + + A human-readable name for the module. + + + + + + A detailed description of the modules purpose. + + + + + + The modules version number. A suggested format is: + <p> + major.minor.patch.build.status + </p><p> + where status is one of + <ul> + <li>vc: version controlled (pre-alpha), build can be a serial revision number, if any (like svn might have).</li> + <li>a: alpha</li> + <li>b: beta</li> + <li>rc: release candidate</li> + <li>fcs: first customer ship</li> + </ul> + </p> + + + + + + + A URL pointing to a documentation or home page of the module. + + + + + + The type of license or a URL containing the license. + + + + + + The author(s) of the command line module. + + + + + + Acknowledgements for funding agency, employer, colleague, etc. + + - + + + Starts a group of parameters. + + @@ -34,44 +96,74 @@ =================================================================== --> + + Starts a group of parameters. + + - - + + + A short string used as the label for this group. + + + + + + A description of this parameter group. + + + - - + + + - - + + + + + + + - - - + + + + + + + - + + - + + + This value is usually used in GUI generators to decide + if the parameters belonging to this group should be initially hidden to the user or not. + + + + This type specifies elements common to all parameter types. + + + + The unique name (within this module) of the parameter. This is only used internally. + + @@ -93,20 +193,54 @@ + + You must either specify "flag" or "longflag" (or both) or "index". + - + + + An integer starting at 0, that specifies a module argument that has no flags. + The index value 1000 is reserved as a marker for output parameters (see the "channel" element) to indicate that + this parameter is used to return results during the execution of this module and does not need to be set. + + - - - + + + A brief description of the parameter. + + + + + + A label for parameter. + + + + + + A default value for the parameter. The default must be a type that is compatible with the + parameter type. The vector parameters are specified as comma separated values of the atomic parameter type. + + + + + Specifies whether the parameter is an input or output parameter. Output parameters can for + example specify file paths where to write output data (e.g. using the "image" element) or they can represent + "simple return parameters", indicated by providing an "index" of 1000. The current values of suche simple return + parameters are not passed to the module during its execution. Rather, the module itself reports these parameter + values during execution. + + + @@ -128,6 +262,10 @@ =================================================================== --> + + This type represents vectors of integers, floats, and doubles and can contain + constraints on the domain of valid values for the vector elements. + @@ -144,9 +282,18 @@ =================================================================== --> + + Parameters of this type are allowed to be passed multiple times with + different values to the module if the attribute "multiple" is set to true. Note that if such + a parameter has no flags, its values must be passed as the last arguments to the module. + - + + + Allows this parameter to occur multiple times. + + @@ -158,6 +305,10 @@ =================================================================== --> + + This type represents integers, floats, and doubles and can contain + constraints on the domain of valid values. + @@ -174,10 +325,18 @@ =================================================================== --> + + Restricts the valid parameter value to one and only one element out of + a specified descrete set of values. + - + + + Defines one possible enumeration value. + + @@ -190,9 +349,23 @@ =================================================================== --> + + A parameter describing a point or region in 3D with a specified coordinate system. + + + Specifies the coordinate system. If unspecified, the executing module is free to interpret the + coordinates in the most appropriate way. For more information about the different systems, see + <a href="http://www.slicer.org/slicerWiki/index.php/Coordinate_systems">Coordinate Systems</a>. + <ul> + <li><b>ras</b> (Right, Anterior, Superior) coordinate system.</li> + <li><b>ijk</b> image coordinate system.</li> + <li><b>lps</b> (Left, Posterior, Superior) coordinate system.</li> + </ul> + + @@ -214,8 +387,15 @@ - + + + A comma separated list of allowed file extensions. + + + + Optionally specifies the allowed geometry type. + @@ -230,14 +410,18 @@ - + + + A comma separated list of allowed file extensions (e.g. "nrrd,mhd"). + + @@ -252,6 +436,9 @@ + + Optionally specifies the allowed image type. + @@ -280,10 +467,23 @@ + + A single character flag (e.g. "s", "W", etc.). Not required if "longFlag" is specified. + - - + + + A comma separated list of aliases. Can be used to provide different flags for the same parameter. + + + + + + A comma separated list of deprecated aliases. When invoking a module with one of these aliases, + the callee will be notified about the new preferred flag name. + + @@ -295,20 +495,51 @@ + + A multi-character flag (e.g. "spacing", "Watcher", etc.). Not required if "flag" is specified. + - - + + + A comma separated list of aliases. Can be used to provide different long flags for the same parameter. + + + + + + A comma separated list of deprecated aliases. When invoking a module with one of these aliases, + the callee will be notified about the new preferred long flag name. + + + + + Constraints on the allowed parameter value for scalar types and their vector variants. + - - - + + + The minimum allowed value for the parameter. If not specified, the minimum is the smallest + possible value for the parameter type. + + + + + The maximum allowed value for the parameter. If not specified, the maximum is the largest + possible value for the parameter type. + + + + + The increment for the parameter. + + diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h index 8c0b408761..82d3e32ceb 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleBackend.h @@ -31,12 +31,17 @@ template class QList; class QUrl; /** - * \class ctkCmdLineModuleBackend - * \brief Abstract base class for all back-end command line module + * @ingroup CommandLineModulesCore_API + * + * @brief Abstract base class for all back-end command line module * implementations. - * \ingroup CommandLineModulesCore - * \see ctkCmdLineModuleBackendLocalProcess - * \see ctkCmdLineModuleBackendFunctionPointer + * + * A back-end is responsible for providing the XML module description for a + * given URL and its "timestamp". It also knows how to actually run a module, + * using the current parameter values provided by a ctkCmdLineModuleFrontend instance. + * + * @see ctkCmdLineModuleBackendLocalProcess + * @see ctkCmdLineModuleBackendFunctionPointer */ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend { @@ -57,8 +62,7 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend virtual QString description() const = 0; /** - * @brief Returns a list of the capabilities or the types of things - * that this back-end can run. + * @brief Returns a list of URL schemes this back-end can handle. * @return A list of "schemes", meaning the capabilities. */ virtual QList schemes() const = 0; @@ -76,7 +80,9 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend * @return The raw XML parameter description. * * This method may be concurrently called by the ctkCmdLineModuleManager and - * must be thread-safe. + * must be thread-safe. Implementations must not use any caching mechanism, + * as caching is done by the ctkCmdLineModuleManager itself, checking the + * return value of timeStamp(). * */ virtual QByteArray rawXmlDescription(const QUrl& location) = 0; @@ -87,7 +93,11 @@ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleBackend /** * @brief The main method to actually execute the back-end process. - * @param A pointer to a front end implementation. + * @param frontend A pointer to a front end implementation. + * + * Implementations must execute the actual task of running the module asynchronously + * and return from this method immediately. After returning from this method, + * accessing the frontend pointer is not guaranteed to be safe. */ virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend) = 0; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h index b782875007..ad895ba28f 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleCache_p.h @@ -32,7 +32,7 @@ class QUrl; * \class ctkCmdLineModuleCache * \brief Private non-exported class to contain a cache of * XML descriptions and time-stamps. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API */ class ctkCmdLineModuleCache { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h index 2eac369024..39bd3025f5 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleConcurrentHelpers.h @@ -29,7 +29,7 @@ class ctkCmdLineModuleManager; /** - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * * \brief A function object for concurrently adding modules. */ @@ -51,7 +51,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleConcurrentRegister }; /** - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * * \brief A function object for concurrently removing modules. */ diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h index ff7b722ab9..cb1c6041a7 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDefaultPathBuilder.h @@ -31,7 +31,7 @@ struct ctkCmdLineModuleDefaultPathBuilderPrivate; * \class ctkCmdLineModuleDefaultPathBuilder * \brief Builds up a list of directory paths to search for command * line modules. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * \author m.clarkson@ucl.ac.uk * * Implements the following basic strategy, depending on which boolean diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h index 51c2d71559..fb65e2c2a6 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDescription.h @@ -37,7 +37,7 @@ class ctkCmdLineModuleParameter; /** * \class ctkCmdLineModuleDescription * \brief Description of the parameters of a command line module. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * * The parameters can be used for automated GUI generation or execution * of the module, and are directly related to the XML description used to diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h index 9d8f1dd883..7d7ae71e60 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher.h @@ -35,7 +35,7 @@ class ctkCmdLineModuleDirectoryWatcherPrivate; * \class ctkCmdLineModuleDirectoryWatcher * \brief Provides directory scanning to automatically load new modules * into a ctkCmdLineModuleManager. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * \author m.clarkson@ucl.ac.uk * * This class provides directory scanning and automatic loading of command diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h index ffbe579d6b..3d74d9d067 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleDirectoryWatcher_p.h @@ -34,7 +34,7 @@ class QFileSystemWatcher; /** * \class ctkCmdLineModuleDirectoryWatcherPrivate * \brief Private implementation class implementing directory scanning to load new modules into a ctkCmdLineModuleManager. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * \author m.clarkson@ucl.ac.uk */ class ctkCmdLineModuleDirectoryWatcherPrivate : public QObject diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h index 32409da16e..5eac7c91ec 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontend.h @@ -39,7 +39,13 @@ struct ctkCmdLineModuleFrontendPrivate; * \class ctkCmdLineModuleFrontend * \brief Abstract base class for all front-end command * line module implementations. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API + * + * A module front-end represents a set of current parameter values for a specific + * module. A front-end instance is usually associated with a graphical user interface, + * accessible via guiHandle(). This allows users to interactively change parameter values + * of the module. + * * \see ctkCmdLineModuleFrontendQtGui * \see ctkCmdLineModuleFrontendQtWebKit */ @@ -85,8 +91,11 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject }; enum ParameterFilter { + /** Parameters with channel = "input" */ Input = 0x01, + /** Parameter with channel = "output" */ Output = 0x02, + /** A convenience enum value combining Input and Output. */ All = Input | Output }; Q_DECLARE_FLAGS(ParameterFilters, ParameterFilter) @@ -94,10 +103,13 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject ~ctkCmdLineModuleFrontend(); /** - * @brief Returns the GUI representation, currently supporting only - * QObject subclasses. - * @return The GUI that can then be embeded in an applicaiton - * window for instance. + * @brief Returns the GUI representation. + * @return A GUI handle that can then be embeded in an application window for instance. + * + * The returned object is a handle to the real GUI toolkit specific object representing + * the user interface. For Qt based front-ends, the returned object is usually a QWidget + * instance pointing to the main container widget for the GUI. See the documentation + * of the front-end sub-class for specific information. */ virtual QObject* guiHandle() const = 0; @@ -169,14 +181,16 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject virtual void setValues(const QHash& values); /** - * @brief Indicates if the underlying process is currently active. - * @return true if running and false otherwise. + * @brief Indicates if the currently associated ctkCmdLineModuleFuture object + * is in state "running". + * @return \c true if running and \c false otherwise. */ bool isRunning() const; /** - * @brief Indicates if the underlying process is currently paused. - * @return true if paused and false otherwise. + * @brief Indicates if the currently associated ctkCmdLineModuleFuture Object + * is in state "paused". + * @return \c true if paused and \c false otherwise. */ bool isPaused() const; @@ -200,7 +214,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject /** * @brief This signal is emitted whenever a parameter value is changed by using - * the ctkCmdLineModuleFrontent class. + * the ctkCmdLineModuleFrontend class. * @param parameter The parameter name. * @param value The new parameter value. * @@ -224,12 +238,6 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontend : public QObject */ ctkCmdLineModuleFrontend(const ctkCmdLineModuleReference& moduleRef); - /** - * @brief Sets the ctkCmdLineModuleFuture which effectively - * contains the backend that is run. - */ - void setFuture(const ctkCmdLineModuleFuture& future); - private Q_SLOTS: /** @@ -242,6 +250,14 @@ private Q_SLOTS: */ virtual void resultReady(const ctkCmdLineModuleResult& result); +private: + + /** + * @brief Sets the ctkCmdLineModuleFuture which effectively + * contains the backend that is run. + */ + void setFuture(const ctkCmdLineModuleFuture& future); + private: Q_DISABLE_COPY(ctkCmdLineModuleFrontend) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h index cb36740d8a..4223e2804c 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFrontendFactory.h @@ -30,16 +30,34 @@ class ctkCmdLineModuleReference; /** * \class ctkCmdLineModuleFrontendFactory * \brief Factory class to create new front-ends. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API + * + * Front-end implementors are advised to create and export a sub-class of + * this class to unify the creation process of front-ends. + * * \see ctkCmdLineModuleFrontend */ struct CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFrontendFactory { virtual ~ctkCmdLineModuleFrontendFactory(); + /** + * @brief Get the name of this factory. + * @return The factory name. + */ virtual QString name() const = 0; + + /** + * @brief Get the description for this factory. + * @return A factory description. + */ virtual QString description() const = 0; + /** + * @brief Creates front-end instances. + * @param moduleRef The module reference for which to create a front-end. + * @return The created front-end or NULL if creation failed. + */ virtual ctkCmdLineModuleFrontend* create(const ctkCmdLineModuleReference& moduleRef) = 0; }; diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h index 65cab95b1b..a83e117892 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleFuture.h @@ -30,14 +30,15 @@ /** * \class ctkCmdLineModuleFuture - * \brief QFuture sub-class with in addition canCancel() and canPause(). - * \ingroup CommandLineModulesCore + * \brief QFuture sub-class for enhanced communication with running modules. + * \ingroup CommandLineModulesCore_API * + * Please see the QFuture documentation of Qt for details. This sub-class provides + * additional query methods to check if a module can be paused and/or canceled and + * also provides the ability to retrieve the arbitrary output and error data + * from the module. * - * QFuture sub-class with two additional methods: - * - * - bool canCancel() - * - bool canPause() + * \see ctkCmdLineModuleFutureWatcher */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFuture : public QFuture { @@ -45,12 +46,32 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleFuture : public QFuturevalidationMode argument is set to SKIP_VALIDATION, no XML validation + * takes place and certain front-ends might fail to generate a GUI. If it is set to + * WEAK_VALIDATION, module registrations will proceed on error but the error status + * is available via ctkCmdLineModuleReference::xmlValidationErrorString(). + */ + ctkCmdLineModuleManager(ValidationMode validationMode = STRICT_VALIDATION, + const QString& cacheDir = QString()); ~ctkCmdLineModuleManager(); + /** + * @brief Registers a new back-end. + * @param backend The new back-end. + * @throws ctkInvalidArgumentException if another back-end was already registered handling + * one of the URL schemes this back-end claims to handle. + */ void registerBackend(ctkCmdLineModuleBackend* backend); + /** + * @brief Registers a module, identified by the give URL. + * @param location The URL for the new module. + * @return A module reference. + * @throws ctkInvalidArgumentException if no back-end for the given URL scheme was registered + * or the XML description for the module is invalid. + */ ctkCmdLineModuleReference registerModule(const QUrl& location); + + /** + * @brief Unregister a previously registered module. + * @param moduleRef The reference for the module to unregister. + * + * This method does nothing if the module reference moduleRef is invalid or + * reference an un-registered module. + */ void unregisterModule(const ctkCmdLineModuleReference& moduleRef); + /** + * @brief Returns a ctkCmdLineModuleReference object for the given URL. + * @param location The location URL for which to get a module reference. + * @return The module reference for the location or an invalid module reference + * if no module was registered under the given location URL. + */ ctkCmdLineModuleReference moduleReference(const QUrl& location) const; + + /** + * @brief Returns module references for all currently registered modules. + * @return A list of module references. + */ QList moduleReferences() const; + /** + * @brief Run a module front-end. + * @param frontend The module front-end to run. + * @return A ctkCmdLineModuleFuture object which can be used to interact with the + * running front-end. + * + * This method takes a ctkCmdLineModuleFrontend pointer and uses the registered back-end + * for this module's location URL scheme to run it asynchronously. The returned future object + * is the only way to interact with the task started by the specific back-end. + * + * @see ctkCmdLineModuleFuture + * @see ctkCmdLineModuleFutureWatcher + */ ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* frontend); Q_SIGNALS: + /** + * @brief This signal is emitted whenever a module is registered. + */ void moduleRegistered(const ctkCmdLineModuleReference&); + + /** + * @brief This signal is emitted whenever a module is un-registered. + */ void moduleUnregistered(const ctkCmdLineModuleReference&); private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h index 5801218170..1acd17cdee 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameter.h @@ -33,7 +33,7 @@ struct ctkCmdLineModuleParameterPrivate; /** * \class ctkCmdLineModuleParameter * \brief Single parameter to a module, like a threshold of a filter. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * * * ctkCmdLineModuleParameter describes a single parameter for a diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h index 194ae42c50..b2dcd9dc81 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleParameterGroup.h @@ -34,7 +34,7 @@ struct ctkCmdLineModuleParameterGroupPrivate; /** * \class ctkCmdLineModuleParameterGroup * \brief Group of parameters - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleParameterGroup { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h index ea9e500cdc..8105190afe 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleReference.h @@ -34,29 +34,60 @@ struct ctkCmdLineModuleReferencePrivate; /** * \class ctkCmdLineModuleReference * \brief Defines a reference or handle to a module, including location, - * XML, description and access to the backend. - * \ingroup CommandLineModulesCore + * XML, description and access to the associated backend. + * \ingroup CommandLineModulesCore_API + * + * Instances of this class reference registered modules and can be used + * to retrieve information about their parameters or to create a specific + * front-end. */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleReference { public: + /** + * @brief Creates an invalid module reference. + */ ctkCmdLineModuleReference(); ~ctkCmdLineModuleReference(); ctkCmdLineModuleReference(const ctkCmdLineModuleReference& ref); ctkCmdLineModuleReference& operator=(const ctkCmdLineModuleReference& ref); + /** + * @brief Conversion operator to test the validity of this module reference. + */ operator bool() const; + /** + * @brief Get the module description for the parameters. + * @return The XML description as a class representation. + */ ctkCmdLineModuleDescription description() const; + /** + * @brief Get the raw XML description, as supplied by the back-end. + * @return The raw XML description. + */ QByteArray rawXmlDescription() const; + /** + * @brief Retrieve a validation error string. + * @return A non-empty string describing the validation error, if validation + * of the XML description was not successful. + */ QString xmlValidationErrorString() const; + /** + * @brief Get the URL under which the module was registered. + * @return The module location. + */ QUrl location() const; + /** + * @brief Get the back-end which was registered to handle this module. + * @return The back-end handling this module. + */ ctkCmdLineModuleBackend* backend() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h index 59b6b7b5f2..3f8c4078d5 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleResult.h @@ -26,9 +26,15 @@ #include /** - * \class ctkCmdLineModuleResult - * \brief Describes the output of a command line module. - * \ingroup CommandLineModulesCore + * @ingroup CommandLineModulesCore_API + * + * @brief Describes a reported result of a command line module. + * + * This class wraps a specific result reported by a running module via a + * ctkCmdLineModuleFuture instance. + * + * @see ctkCmdLineModuleFuture + * @see ctkCmdLineModuleFutureWatcher */ class ctkCmdLineModuleResult { @@ -45,8 +51,17 @@ class ctkCmdLineModuleResult return Parameter == other.Parameter && Value == other.Value; } - inline QString parameter() const { return Parameter; } - inline QVariant value() const { return Value; } + /** + * @brief Get the name of the output parameter for which this result was reported. + * @return The output parameter name. + */ + QString parameter() const; + + /** + * @brief Get the result value. + * @return The result value. + */ + QVariant value() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h index cc3553a1b0..8eefc5b698 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleRunException.h @@ -31,7 +31,7 @@ /** * \class ctkCmdLineModuleRunException * \brief Exception class to describe problems with running the module. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleRunException : public QtConcurrent::Exception, public ctkException diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h index c1ca9e8d13..21f3454e58 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlException.h @@ -29,7 +29,7 @@ /** * \class ctkCmdLineModuleXmlException * \brief Exception class to describe problems with XML processing. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API */ CTK_DECLARE_EXCEPTION(CTK_CMDLINEMODULECORE_EXPORT, ctkCmdLineModuleXmlException, ctkException) diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h index a9d3d5d8ad..8ed36dfdae 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlMsgHandler_p.h @@ -27,7 +27,7 @@ /** * \class QAbstractMessageHandler * \brief Class to handle an XML message. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API */ class ctkCmdLineModuleXmlMsgHandler : public QAbstractMessageHandler { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h index b90939e91a..25dfbda30d 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlParser_p.h @@ -34,7 +34,7 @@ class QIODevice; /** * \class ctkCmdLineModuleXmlParser * \brief Performs XML parsing, loading data into a ctkCmdLineModuleDescription - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API * \see ctkCmdLineModuleDescription */ class ctkCmdLineModuleXmlParser diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h index c45185703b..38d95f8ddc 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.h @@ -34,7 +34,11 @@ class QProcess; /** * \class ctkCmdLineModuleXmlProgressWatcher * \brief Provides progress updates of a module. - * \ingroup CommandLineModulesCore + * \ingroup CommandLineModulesCore_API + * + * This class is usually only used by back-end implementators for modules + * which can report progress and results in the form of XML fragments written + * to a QIODevice. */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlProgressWatcher : public QObject { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h index 26a01382df..759ac53cef 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlValidator.h @@ -31,9 +31,10 @@ class ctkCmdLineModuleXmlValidatorPrivate; class QIODevice; /** - * \class ctkCmdLineModuleXmlValidator - * \brief Provides XML validation, comparing a modules XML to an .xsd file - * \ingroup CommandLineModulesCore + * @ingroup CommandLineModulesCore_API + * + * @brief Provides validation of an XML document against an XML schema. + * */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlValidator { @@ -43,14 +44,40 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXmlValidator ctkCmdLineModuleXmlValidator(QIODevice* input = 0); ~ctkCmdLineModuleXmlValidator(); + /** + * @brief Set the XML input. + * @param input The Xml input. + */ void setInput(QIODevice* input); + + /** + * @brief Get the XML input device. + * @return The XML input device. + */ QIODevice* input() const; + /** + * @brief Set the XML schema to be used during validation. + * @param input The XML schema. + */ void setInputSchema(QIODevice* input); + /** + * @brief Validate the XML input against the XML schema set via setInputSchema(). + * @return \c true if validation was successful, \c false otherwise. + */ virtual bool validateInput(); + /** + * @brief Get the error flag. + * @return \c true if an error occured during validation, \c false otherwise. + */ virtual bool error() const; + + /** + * @brief Get the error string. + * @return A description of the validation error, if any. + */ virtual QString errorString() const; private: diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp index f4e4d4f18e..aa9906a6bc 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.cpp @@ -279,6 +279,12 @@ void ctkCmdLineModuleXslTransform::setValidateOutput(bool validate) d->Validate = validate; } +//---------------------------------------------------------------------------- +bool ctkCmdLineModuleXslTransform::validateOutput() const +{ + return d->Validate; +} + //---------------------------------------------------------------------------- bool ctkCmdLineModuleXslTransform::error() const { diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h index 55c2b1e013..6fb0fdf58c 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXslTransform.h @@ -31,9 +31,14 @@ class ctkCmdLineModuleXslTransformPrivate; class QIODevice; /** - * \class ctkCmdLineModuleXslTransform - * \brief Provides a transformation from XML to the Qt ui file format. - * \ingroup CommandLineModulesCore + * @ingroup CommandLineModulesCore_API + * + * @brief Transforms a given XML input using an XML stylesheet. + * + * You must call setInput(), setOutput() and setXslTransformation() before + * calling transform(). + * + * @see ctkCmdLineModuleXmlValidator */ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform : public ctkCmdLineModuleXmlValidator @@ -44,14 +49,31 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform ctkCmdLineModuleXslTransform(QIODevice* input = 0, QIODevice* output = 0); virtual ~ctkCmdLineModuleXslTransform(); + /** + * @brief Set the output device to which the transformation will be written. + * @param output The output device. + * + * If no output device is set, a default device will be used. + */ void setOutput(QIODevice* output); + + /** + * @brief Get the output device to which the transformation will be written. + * @return The output device. + */ QIODevice* output() const; + /** + * @brief Set an XML schema for output validation. + * @param output The XML schema against which the transformation will be validated. + * + * Output validation will only be done if validateOutput() returns \c true. + */ void setOutputSchema(QIODevice* output); /** - * @brief Returns \code true if the XSL output will be formatted. - * @return \code true if the ouptut will be formatted, \code false otherwise. + * @brief Returns \c true if the XSL output will be formatted. + * @return \c true if the ouptut will be formatted, \c false otherwise. */ bool formatXmlOutput() const; @@ -60,7 +82,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform * * It is assumed that the XSL output is valid XML. The output will be * formatted with an indentation depth of four spaces. Note that setting - * \e format to \code true increases compuational overhead and memory + * \c format to \c true increases compuational overhead and memory * requirements and is usually only done for testing or debugging purposes. */ void setFormatXmlOutput(bool format); @@ -69,7 +91,8 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform * @brief Transforms an XML input via a XSL transformation. * * This method assumes that the input set via setInput() or supplied - * in the constructor is a valid, non empty XML fragment. + * in the constructor is a valid, non empty XML fragment and that setOutput() + * and setXslTransformation() was called with non-null arguments. * * @return */ @@ -82,7 +105,7 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform * to transform the input without setting a transformation will result in * runtime errors. * - * @param The XSL transformation. + * @param transformation The XSL transformation. */ void setXslTransformation(QIODevice* transformation); @@ -106,19 +129,37 @@ class CTK_CMDLINEMODULECORE_EXPORT ctkCmdLineModuleXslTransform */ void bindVariable(const QString& name, const QVariant& value); + /** + * @brief Sets the output validation mode. + * @param validate If \c true, the output will be validated against the XML schema + * provided via setOutputSchema(). If \c validate is \c false, no output + * validation takes place. + */ void setValidateOutput(bool validate); - /** @brief returns true if an error occured - * transform() sets the error flag if an error occured when transforming the - * XML file into XSL. - * \sa errorString + /** + * @brief Get the output validation mode. + * @return \c true if the output will be validated, \c false otherwise. + */ + bool validateOutput() const; + + /** + * @brief Returns true if an error occured. + * + * transform() sets the error flag if an error occured when transforming the + * XML file into XSL or validating the transformation. + * + * @sa errorString */ virtual bool error() const; - /** @brief Error message if any - * transform() sets the error message if an error occured when transforming + /** + * @brief Returns the error message if any. + * + * transform() sets the error message if an error occured when transforming * the XML file into XSL. - * \sa error + * + * @sa error */ virtual QString errorString() const; diff --git a/Libs/CommandLineModules/Documentation/Backends.md b/Libs/CommandLineModules/Documentation/Backends.md new file mode 100644 index 0000000000..d408cef696 --- /dev/null +++ b/Libs/CommandLineModules/Documentation/Backends.md @@ -0,0 +1,7 @@ +Backends {#CommandLineModulesBackEnds_Page} +======== + +Here is a list of available back-ends: + +- \subpage CommandLineModulesBackendFunctionPointer_Page +- \subpage CommandLineModulesBackendLocalProcess_Page diff --git a/Libs/CommandLineModules/Documentation/CMakeLists.txt b/Libs/CommandLineModules/Documentation/CMakeLists.txt new file mode 100644 index 0000000000..635d769ca2 --- /dev/null +++ b/Libs/CommandLineModules/Documentation/CMakeLists.txt @@ -0,0 +1,12 @@ + +# Copy the xs3p.xsl stylesheet which is used in .xsd files to generate nice +# html output when opened in a browser. +execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xs3p.xsl + ${CTK_BINARY_DIR}/Documentation/html/xs3p.xsl) + +if (BUILD_TESTING AND + CTK_LIB_CommandLineModules/Core AND CTK_LIB_CommandLineModules/Backend/LocalProcess) + + # Compile source code snippets + add_subdirectory(Snippets) +endif() diff --git a/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox b/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox index 59a97bc284..9be6780bc6 100644 --- a/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox +++ b/Libs/CommandLineModules/Documentation/CTKCommandLineModules.dox @@ -1,34 +1,54 @@ /** -\defgroup CommandLineModules Command Line Modules +\defgroup CommandLineModules_Group Command Line Modules \ingroup Projects -CTK provides an API for interfacing with command line modules through a -self-describing XML description of the supported command line arguments. +See the sub-modules for detailed API documentation of the available front and back-ends. -\defgroup CommandLineModulesCore Command Line Module Core +For a high-level overview, see \ref CommandLineModules_Page. + +\defgroup CommandLineModulesCore_API Command Line Module Core API \ingroup Libs -\ingroup CommandLineModules +\ingroup CommandLineModules_Group + +This is a list of types provided by the CTK Command Line Module Core library. See the +\ref CommandLineModulesCore_Page library page for general information. -\defgroup CommandLineModulesBackEnd Command Line Module Back-End +\defgroup CommandLineModulesBackEnd_Group Command Line Module Back-Ends \ingroup Libs -\ingroup CommandLineModules +\ingroup CommandLineModules_Group + +This module groups back-end implementations. See ctkCmdLineModuleBackend for details about back-ends. + +\defgroup CommandLineModulesBackendFunctionPointer_API Function Pointer API (experimental) +\ingroup CommandLineModulesBackEnd_Group -\defgroup CommandLineModulesBackendFunctionPointer Command Line Module Function Pointer -\ingroup CommandLineModulesBackEnd +This is a list of types provided by the CTK Command Line Module Function Pointer Backend library. See the +\ref CommandLineModulesBackendFunctionPointer_Page library page for general information. -\defgroup CommandLineModulesBackendLocalProcess Command Line Module Local Process -\ingroup CommandLineModulesBackEnd +\defgroup CommandLineModulesBackendLocalProcess_API Local Process API +\ingroup CommandLineModulesBackEnd_Group -\defgroup CommandLineModulesFrontEnd Command Line Module Front-End +This is a list of types provided by the CTK Command Line Module Local Process Backend library. See the +\ref CommandLineModulesBackendLocalProcess_Page library page for general information. + +\defgroup CommandLineModulesFrontEnd_Group Command Line Module Front-Ends \ingroup Libs -\ingroup CommandLineModules +\ingroup CommandLineModules_Group + +This module groups front-end implementations. See ctkCmdLineModuleFrontend for details about front-ends. + +\defgroup CommandLineModulesFrontendQtGui_API QtGui API +\ingroup CommandLineModulesFrontEnd_Group + +This is a list of types provided by the CTK Command Line Module Qt Gui Frontend library. See the +\ref CommandLineModulesFrontendQtGui_Page library page for general information. -\defgroup CommandLineModulesFrontendQtGui Command Line Module QtGui -\ingroup CommandLineModulesFrontEnd +\defgroup CommandLineModulesFrontendQtWebKit_API QtWebKit API (experimental) +\ingroup CommandLineModulesFrontEnd_Group -\defgroup CommandLineModulesFrontendQtWebKit Command Line Module QtWebKit -\ingroup CommandLineModulesFrontEnd +This is a list of types provided by the CTK Command Line Module Qt WebKit Frontend library. See the +\ref CommandLineModulesFrontendQtWebKit_Page library page for general information. */ diff --git a/Libs/CommandLineModules/Documentation/Frontends.md b/Libs/CommandLineModules/Documentation/Frontends.md new file mode 100644 index 0000000000..b730296704 --- /dev/null +++ b/Libs/CommandLineModules/Documentation/Frontends.md @@ -0,0 +1,7 @@ +Frontends {#CommandLineModulesFrontEnds_Page} +========= + +Here is a list of available front-ends: + +- \subpage CommandLineModulesFrontendQtGui_Page +- \subpage CommandLineModulesFrontendQtWebKit_Page diff --git a/Libs/CommandLineModules/Documentation/Snippets/CMakeLists.txt b/Libs/CommandLineModules/Documentation/Snippets/CMakeLists.txt new file mode 100644 index 0000000000..fc9df1623d --- /dev/null +++ b/Libs/CommandLineModules/Documentation/Snippets/CMakeLists.txt @@ -0,0 +1,19 @@ + +set(_base_src_include_dir ${CMAKE_SOURCE_DIR}/Libs/CommandLineModules) +set(_base_bin_include_dir ${CMAKE_BINARY_DIR}/Libs/CommandLineModules) + +include_directories( + ${CTKCore_SOURCE_DIR} + ${CTKCore_BINARY_DIR} + ${_base_src_include_dir}/Core + ${_base_bin_include_dir}/Core + ${_base_src_include_dir}/Backend/LocalProcess + ${_base_bin_include_dir}/Backend/LocalProcess + ${_base_src_include_dir}/Frontend/QtGui + ${_base_bin_include_dir}/Frontend/QtGui +) + +ctkFunctionCompileSnippets("${CMAKE_CURRENT_SOURCE_DIR}" + CTKCommandLineModulesBackendLocalProcess + CTKCommandLineModulesFrontendQtGui +) diff --git a/Libs/CommandLineModules/Documentation/Snippets/ModuleManager/main.cpp b/Libs/CommandLineModules/Documentation/Snippets/ModuleManager/main.cpp new file mode 100644 index 0000000000..205a6aaafb --- /dev/null +++ b/Libs/CommandLineModules/Documentation/Snippets/ModuleManager/main.cpp @@ -0,0 +1,112 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleBackendLocalProcess.h" +#include "ctkCmdLineModuleFrontendFactoryQtGui.h" +#include "ctkCmdLineModuleFrontendQtGui.h" +#include "ctkCmdLineModuleFuture.h" +#include "ctkException.h" +#include "ctkCmdLineModuleRunException.h" + +#include +#include +#include +#include +#include + +#include + +int main(int argc, char** argv) +{ + QApplication myApp(argc, argv); + myApp.setOrganizationName("CommonTK"); + myApp.setApplicationName("ModuleManagerSnippet"); + + // [instantiate-mm] + // Instantiate a ctkCmdLineModuleManager class. + ctkCmdLineModuleManager moduleManager( + // Use "strict" validation mode, rejecting modules with non-valid XML descriptions. + ctkCmdLineModuleManager::STRICT_VALIDATION, + // Use the default cache location for this application + QDesktopServices::storageLocation(QDesktopServices::CacheLocation) + ); + // [instantiate-mm] + + // [register-backend] + // Instantiate a back-end for running executable modules in a local process. + // This back-end handles the "file" Url scheme. + QScopedPointer processBackend(new ctkCmdLineModuleBackendLocalProcess); + + // Register the back-end with the module manager. + moduleManager.registerBackend(processBackend.data()); + // [register-backend] + + // [register-module] + ctkCmdLineModuleReference moduleRef; + try + { + // Register a local executable as a module, the ctkCmdLineModuleBackendLocalProcess + // can handle it. + moduleRef = moduleManager.registerModule(QUrl::fromLocalFile("C:/modules/MyModule.exe")); + } + catch (const ctkInvalidArgumentException& e) + { + // Module validation failed. + qDebug() << e; + return EXIT_FAILURE; + } + // [register-module] + + // [create-frontend] + // We use the "Qt Gui" frontend factory. + QScopedPointer frontendFactory(new ctkCmdLineModuleFrontendFactoryQtGui); + myApp.addLibraryPath(QCoreApplication::applicationDirPath() + "/../"); + + QScopedPointer frontend(frontendFactory->create(moduleRef)); + + // Create the actual GUI representation. + QWidget* gui = qobject_cast(frontend->guiHandle()); + // [create-frontend] + Q_UNUSED(gui); + + // Now try and run the module (using the default values for the parameters) + // and print out any reported output and results. + // [run-module] + try + { + ctkCmdLineModuleFuture future = moduleManager.run(frontend.data()); + future.waitForFinished(); + qDebug() << "Console output:"; + qDebug() << future.readAllOutputData(); + qDebug() << "Error output:"; + qDebug() << future.readAllErrorData(); + qDebug() << "Results:"; + qDebug() << future.results(); + } + catch (const ctkCmdLineModuleRunException& e) + { + qWarning() << e; + } + // [run-module] + + return EXIT_SUCCESS; +} diff --git a/Libs/CommandLineModules/Documentation/xs3p.xsl b/Libs/CommandLineModules/Documentation/xs3p.xsl new file mode 100644 index 0000000000..2b789179a4 --- /dev/null +++ b/Libs/CommandLineModules/Documentation/xs3p.xsl @@ -0,0 +1,8520 @@ + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + true + + + true + + + true + + + true + + + true + + + false + + + false + + + + + + + + + + + + + + + http://www.w3.org/2001/XMLSchema + + + http://www.w3.org/XML/1998/namespace + + + 1.5 + + + 0.5 + + + XML Schema Documentation + + + + type_ + + attribute_ + + attributeGroup_ + + + + element_ + + key_ + + group_ + + notation_ + + ns_ + + + + term_ + + + + + + + + + + + + true + +'linksFile' variable must be provided if either +'searchIncludedSchemas' or 'searchImportedSchemas' is true. + + + + + + + + + + + + + + + + + + + + <xsl:value-of select="$actualTitle"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Table of Contents

+ + + + +

Schema Document Properties

+ + + +

Declared Namespaces

+ + + + + + + + + +

Redefined Schema Components

+ +
+ + + + + + + +

Global Declarations

+ + + + +
+ + +

Global Definitions

+ + + + +
+
+ + +

Global Schema Components

+ +
+
+ + + +
+

Legend

+ + +
+
+ + + +
+

Glossary

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PrefixNamespace
+ Default namespace + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
  • + + + + + : + + +
  • +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +var pc = getElementObject("printerControls"); +if (pc != null) { + pc.style.display="block"; +} + + + + + + + +var gc = getElementObject("globalControls"); +if (gc != null) { + gc.style.display="block"; +} + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + +

    + + + + + + + + + + + + + : + + + + +

    +
    + + + + + +
    +
    + + + + + /* IDs of XML Instance Representation boxes */ + + var xiBoxes = new Array( + + + , + + ' + + + + _xibox' + + ); + + + /* IDs of Schema Component Representation boxes */ + + var scBoxes = new Array('schema_scbox' + + , ' + + + + _scbox' + + ); + + + +/** + * Can get the ID of the button controlling + * a collapseable box by concatenating + * this string onto the ID of the box itself. + */ +var B_SFIX = "_button"; + +/** + * Counter of documentation windows + * Used to give each window a unique name + */ +var windowCount = 0; + +/** + * Returns an element in the current HTML document. + * + * @param elementID Identifier of HTML element + * @return HTML element object + */ +function getElementObject(elementID) { + var elemObj = null; + if (document.getElementById) { + elemObj = document.getElementById(elementID); + } + return elemObj; +} + +/** + * Closes a collapseable box. + * + * @param boxObj Collapseable box + * @param buttonObj Button controlling box + */ +function closeBox(boxObj, buttonObj) { + if (boxObj == null || buttonObj == null) { + // Box or button not found + } else { + // Change 'display' CSS property of box + boxObj.style.display="none"; + + // Change text of button + if (boxObj.style.display=="none") { + buttonObj.value=" + "; + } + } +} + +/** + * Opens a collapseable box. + * + * @param boxObj Collapseable box + * @param buttonObj Button controlling box + */ +function openBox(boxObj, buttonObj) { + if (boxObj == null || buttonObj == null) { + // Box or button not found + } else { + // Change 'display' CSS property of box + boxObj.style.display="block"; + + // Change text of button + if (boxObj.style.display=="block") { + buttonObj.value=" - "; + } + } +} + +/** + * Sets the state of a collapseable box. + * + * @param boxID Identifier of box + * @param open If true, box is "opened", + * Otherwise, box is "closed". + */ +function setState(boxID, open) { + var boxObj = getElementObject(boxID); + var buttonObj = getElementObject(boxID+B_SFIX); + if (boxObj == null || buttonObj == null) { + // Box or button not found + } else if (open) { + openBox(boxObj, buttonObj); + // Make button visible + buttonObj.style.display="inline"; + } else { + closeBox(boxObj, buttonObj); + // Make button visible + buttonObj.style.display="inline"; + } +} + +/** + * Switches the state of a collapseable box, e.g. + * if it's opened, it'll be closed, and vice versa. + * + * @param boxID Identifier of box + */ +function switchState(boxID) { + var boxObj = getElementObject(boxID); + var buttonObj = getElementObject(boxID+B_SFIX); + if (boxObj == null || buttonObj == null) { + // Box or button not found + } else if (boxObj.style.display=="none") { + // Box is closed, so open it + openBox(boxObj, buttonObj); + } else if (boxObj.style.display=="block") { + // Box is opened, so close it + closeBox(boxObj, buttonObj); + } +} + +/** + * Closes all boxes in a given list. + * + * @param boxList Array of box IDs + */ +function collapseAll(boxList) { + var idx; + for (idx = 0; idx < boxList.length; idx++) { + var boxObj = getElementObject(boxList[idx]); + var buttonObj = getElementObject(boxList[idx]+B_SFIX); + closeBox(boxObj, buttonObj); + } +} + +/** + * Open all boxes in a given list. + * + * @param boxList Array of box IDs + */ +function expandAll(boxList) { + var idx; + for (idx = 0; idx < boxList.length; idx++) { + var boxObj = getElementObject(boxList[idx]); + var buttonObj = getElementObject(boxList[idx]+B_SFIX); + openBox(boxObj, buttonObj); + } +} + +/** + * Makes all the control buttons of boxes appear. + * + * @param boxList Array of box IDs + */ +function viewControlButtons(boxList) { + var idx; + for (idx = 0; idx < boxList.length; idx++) { + buttonObj = getElementObject(boxList[idx]+B_SFIX); + if (buttonObj != null) { + buttonObj.style.display = "inline"; + } + } +} + +/** + * Makes all the control buttons of boxes disappear. + * + * @param boxList Array of box IDs + */ +function hideControlButtons(boxList) { + var idx; + for (idx = 0; idx < boxList.length; idx++) { + buttonObj = getElementObject(boxList[idx]+B_SFIX); + if (buttonObj != null) { + buttonObj.style.display = "none"; + } + } +} + +/** + * Sets the page for either printing mode + * or viewing mode. In printing mode, the page + * is made to be more readable when printing it out. + * In viewing mode, the page is more browsable. + * + * @param isPrinterVersion If true, display in + * printing mode; otherwise, + * in viewing mode + */ +function displayMode(isPrinterVersion) { + var obj; + if (isPrinterVersion) { + // Hide global control buttons + obj = getElementObject("globalControls"); + if (obj != null) { + obj.style.visibility = "hidden"; + } + // Hide Legend + obj = getElementObject("legend"); + if (obj != null) { + obj.style.display = "none"; + } + obj = getElementObject("legendTOC"); + if (obj != null) { + obj.style.display = "none"; + } + // Hide Glossary + obj = getElementObject("glossary"); + if (obj != null) { + obj.style.display = "none"; + } + obj = getElementObject("glossaryTOC"); + if (obj != null) { + obj.style.display = "none"; + } + + // Expand all XML Instance Representation tables + expandAll(xiBoxes); + // Expand all Schema Component Representation tables + expandAll(scBoxes); + + // Hide Control buttons + hideControlButtons(xiBoxes); + hideControlButtons(scBoxes); + } else { + // View global control buttons + obj = getElementObject("globalControls"); + if (obj != null) { + obj.style.visibility = "visible"; + } + // View Legend + obj = getElementObject("legend"); + if (obj != null) { + obj.style.display = "block"; + } + obj = getElementObject("legendTOC"); + if (obj != null) { + obj.style.display = "block"; + } + // View Glossary + obj = getElementObject("glossary"); + if (obj != null) { + obj.style.display = "block"; + } + obj = getElementObject("glossaryTOC"); + if (obj != null) { + obj.style.display = "block"; + } + + // Expand all XML Instance Representation tables + expandAll(xiBoxes); + // Collapse all Schema Component Representation tables + collapseAll(scBoxes); + + // View Control buttons + viewControlButtons(xiBoxes); + viewControlButtons(scBoxes); + } +} + +/** + * Opens up a window displaying the documentation + * of a schema component in the XML Instance + * Representation table. + * + * @param compDesc Description of schema component + * @param compName Name of schema component + * @param docTextArray Array containing the paragraphs + * of the new document + */ +function viewDocumentation(compDesc, compName, docTextArray) { + var width = 400; + var height = 200; + var locX = 100; + var locY = 200; + + /* Generate content */ + var actualText = "<html>"; + actualText += "<head><title>"; + actualText += compDesc; + if (compName != '') { + actualText += ": " + compName; + } + actualText += "</title></head>"; + actualText += "<body bgcolor=\"#FFFFEE\">"; + // Title + actualText += "<p style=\"font-family: Arial, sans-serif; font-size: 12pt; font-weight: bold; letter-spacing:1px;\">"; + actualText += compDesc; + if (compName != '') { + actualText += ": <span style=\"color:#006699\">" + compName + "</span>"; + } + actualText += "</p>"; + // Documentation + var idx; + for (idx = 0; idx < docTextArray.length; idx++) { + actualText += "<p style=\"font-family: Arial, sans-serif; font-size: 10pt;\">" + docTextArray[idx] + "</p>"; + } + // Link to close window + actualText += "<a href=\"javascript:void(0)\" onclick=\"window.close();\" style=\"font-family: Arial, sans-serif; font-size: 8pt;\">Close</a>"; + actualText += "</body></html>"; + + /* Display window */ + windowCount++; + var docWindow = window.open("", "documentation"+windowCount, "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable,alwaysRaised,dependent,titlebar=no,width="+width+",height="+height+",screenX="+locX+",left="+locX+",screenY="+locY+",top="+locY); + docWindow.document.write(actualText); +} + + + + + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* More-configurable styles */ + +/******** General ********/ + +/* Document body */ +body { + color: Black; + background-color: White; + font-family: Arial, sans-serif; + font-size: 10pt; +} +/* Horizontal rules */ +hr { + color: black; +} +/* Document title */ +h1 { + font-size: 18pt; + letter-spacing: 2px; + border-bottom: 1px #ccc solid; + padding-top: 5px; + padding-bottom: 5px; +} +/* Main section headers */ +h2 { + font-size: 14pt; + letter-spacing: 1px; +} +/* Sub-section headers */ +h3, h3 a, h3 span { + font-size: 12pt; + font-weight: bold; + color: black; +} +/* Table displaying the properties of the schema components or the + schema document itself */ +table.properties th, table.properties th a { + color: black; + background-color: #F99; /* Pink */ +} +table.properties td { + background-color: #eee; /* Gray */ +} + + +/******** Table of Contents Section ********/ + +/* Controls for switching between printing and viewing modes */ +div#printerControls { + color: #963; /* Orange-brown */ +} +/* Controls that can collapse or expand all XML Instance + Representation and Schema Component Representation boxes */ +div#globalControls { + border: 2px solid #999; +} + + +/******** Schema Document Properties Section ********/ + +/* Table displaying the namespaces declared in the schema */ +table.namespaces th { + background-color: #ccc; +} +table.namespaces td { + background-color: #eee; +} +/* Target namespace of the schema */ +span.targetNS { + color: #06C; + font-weight: bold; +} + + +/******** Schema Components' Sections ********/ + +/* Name of schema component */ +.name { + color: #F93; /* Orange */ +} + +/* Hierarchy table */ +table.hierarchy { + border: 2px solid #999; /* Gray */ +} + +/* XML Instance Representation table */ +div.sample div.contents { + border: 2px dashed black; +} + +/* Schema Component Representation table */ +div.schemaComponent div.contents { + border: 2px black solid; +} + + +/******** Glossary Section ********/ + +/* Glossary Terms */ +.glossaryTerm { + color: #036; /* Blue */ +} + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* Printer-version styles */ + +@media print { + +/* Ensures that controls are hidden when printing */ +div#printerControls { + visibility: hidden; +} +div#globalControls { + visibility: hidden; +} +#legend { + display: none; +} +#legendTOC { + display: none; +} +#glossary { + display: none; +} +#glossaryTOC { + display: none; +} + +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* Base styles */ + +/******** General ********/ + +/* Unordered lists */ +ul { + margin-left: 1.5em; + margin-bottom: 0em; +} +/* Tables */ +table { + margin-top: 10px; + margin-bottom: 10px; + margin-left: 2px; + margin-right: 2px; +} +table th, table td { + font-size: 10pt; + vertical-align: top; + padding-top: 3px; + padding-bottom: 3px; + padding-left: 10px; + padding-right: 10px; +} +table th { + font-weight: bold; + text-align: left; +} +/* Table displaying the properties of the schema components or the + schema document itself */ +table.properties { + width: 90%; +} +table.properties th { + width: 30%; +} +/* Boxes that can make its content appear and disappear*/ +div.box { + margin: 1em; +} + /* Box caption */ +div.box span.caption { + font-weight: bold; +} + /* Button to open and close the box */ +div.box input.control { + width: 1.4em; + height: 1.4em; + text-align: center; + vertical-align: middle; + font-size: 11pt; +} + /* Box contents */ +div.box div.contents { + margin-top: 3px; +} + + +/******** Table of Contents Section ********/ + +/* Controls for switching between printing and viewing modes */ +div#printerControls { + white-space: nowrap; + font-weight: bold; + padding: 5px; + margin: 5px; +} +/* Controls that can collapse or expand all XML Instance + Representation and Schema Component Representation boxes */ +div#globalControls { + padding: 10px; + margin: 5px; +} + + +/******** Schema Document Properties Section ********/ + +/* Table displaying the namespaces declared in the schema */ +table.namespaces th { +} +table.namespaces td { +} +/* Target namespace of the schema */ +span.targetNS { +} + + +/******** Schema Components' Sections ********/ + +/* Name of schema component */ +.name { +} + +/* Hierarchy table */ +table.hierarchy { + width: 90%; +} +table.hierarchy th { + font-weight: normal; + font-style: italic; + width: 20%; +} +table.hierarchy th, table.hierarchy td { + padding: 5px; +} + +/* XML Instance Representation table */ +div.sample { + width: 90%; +} +div.sample div.contents { + padding: 5px; + font-family: Courier New, sans-serif; + font-size: 10pt; +} + /* Normal elements and attributes */ +div.sample div.contents, div.sample div.contents a { + color: black; +} + /* Group Headers */ +div.sample div.contents .group, div.sample div.contents .group a { + color: #999; /* Light gray */ +} + /* Type Information */ +div.sample div.contents .type, div.sample div.contents .type a { + color: #999; /* Light gray */ +} + /* Occurrence Information */ +div.sample div.contents .occurs, div.sample div.contents .occurs a { + color: #999; /* Light gray */ +} + /* Fixed values */ +div.sample div.contents .fixed { + color: #063; /* Green */ + font-weight: bold; +} + /* Simple type constraints */ +div.sample div.contents .constraint, div.sample div.contents .constraint a { + color: #999; /* Light gray */ +} + /* Elements and attributes inherited from base type */ +div.sample div.contents .inherited, div.sample div.contents .inherited a { + color: #666; /* Dark gray */ +} + /* Elements and attributes added to or changed from base type */ +div.sample div.contents .newFields { + font-weight: bold; +} + /* Other type of information */ +div.sample div.contents .other, div.sample div.contents .other a { + color: #369; /* Blue */ + font-style: italic; +} + /* Link to open up window displaying documentation */ +div.sample div.contents a.documentation { + text-decoration: none; + padding-left: 3px; + padding-right: 3px; + padding-top: 0px; + padding-bottom: 0px; + font-weight: bold; + font-size: 11pt; + background-color: #FFD; + color: #069; +} + /* Invert colors when hovering over link to open up window + displaying documentation */ +div.sample div.contents a.documentation:hover { + color: #FFD; + background-color: #069; +} + +/* Schema Component Representation table */ +div.schemaComponent { + width: 90%; +} +div.schemaComponent div.contents { + font-family: Courier New, sans-serif; + font-size: 10pt; + padding: 5px; +} + /* Syntax characters */ +div.schemaComponent div.contents { + color: #00f; /* blue */ +} + /* Element and attribute tags */ +div.schemaComponent div.contents .scTag { + color: #933; /* maroon */ +} + /* Element and attribute content */ +div.schemaComponent div.contents .scContent, div.schemaComponent div.contents .scContent a { + color: black; + font-weight: bold; +} + /* Comments */ +div.schemaComponent div.contents .comment { + color: #999; /* Light gray */ +} + +/******** Legend Section ********/ + +div#legend table, div#legend div { + margin-bottom: 3px; +} +div#legend div.hint { + color: #999; /* Light gray */ + width: 90%; + margin-left: 1em; + margin-bottom: 2em; +} + + +/******** Glossary Section ********/ + +/* Glossary Terms */ +.glossaryTerm { + font-weight: bold; +} + + +/******** Footer ********/ + +.footer { + font-size: 8pt; +} + + + + + + +
    +

    Complex Type:

    +
    Schema Component Type
    +
    +
    +

    AusAddress

    +
    Schema Component Name
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Super-types: + Address + < + AusAddress + (by extension) + Parent type: + Address + (derivation method: extension) +
    Sub-types: +
      +
    • + QLDAddress + (by restriction) +
    • +
    +
    Direct sub-types: +
      +
    • + QLDAddress + (by restriction) +
    • +
    +
    +
    If this schema component is a type definition, its type hierarchy is shown in a gray-bordered box.
    + + + + + + + + + + + +
    NameAusAddress
    + Abstract + no
    +
    The table above displays the properties of this schema component.
    + + +
    +
    + XML Instance Representation +
    +
    + <... + + country="Australia" + + >
    + <unitNo> string </unitNo> [0..1]
    + <houseNo> string </houseNo> [1]
    + <street> string </street> [1]
    + Start Choice [1]
    + <city> string </city> [1]
    + <town> string </town> [1]
    + End Choice
    + + <state> AusStates </state> [1]
    + <postcode> string <<pattern = [1-9][0-9]{3}>> </postcode> [1] + + ? + +
    +
    + </...>
    +
    +
    +
    +

    The XML Instance Representation table above shows the schema component's content as an XML instance.

    +
      +
    • The minimum and maximum occurrence of elements and attributes are provided in square brackets, e.g. [0..1].
    • +
    • Model group information are shown in gray, e.g. Start Choice ... End Choice.
    • +
    • For type derivations, the elements and attributes that have been added to or changed from the base type's content are shown in bold.
    • +
    • If an element/attribute has a fixed value, the fixed value is shown in green, e.g. country="Australia".
    • +
    • Otherwise, the type of the element/attribute is displayed. +
        +
      • If the element/attribute's type is in the schema, a link is provided to it.
      • + +
      • For local simple type definitions, the constraints are displayed in angle brackets, e.g. <<pattern = [1-9][0-9]{3}>>.
      • +
      +
    • + +
    • If a local element/attribute has documentation, it will be displayed in a window that pops up when the question mark inside the attribute or next to the element is clicked, e.g. <postcode>.
    • +
      +
    +
    + + +
    +
    + Schema Component Representation +
    +
    + <complexType name="AusAddress">
    + <complexContent>
    + <extension base="Address">
    + <sequence>
    + <element name="state" type="AusStates"/>
    + <element name="postcode">
    + <simpleType>
    + <restriction base="string">
    + <pattern value="[1-9][0-9]{3}"/>
    + </restriction>
    + </simpleType>
    + </element>
    + </sequence>
    + <attribute name="country" type="string" fixed="Australia"/>
    + </extension>
    + </complexContent>
    + </complexType>
    +
    +
    +
    The Schema Component Representation table above displays the underlying XML representation of the schema component. (Annotations are not shown.)
    +
    + + + + + Abstract + Abstract + + (Applies to complex type definitions and element declarations). + An abstract element or complex type cannot used to validate an element instance. + If there is a reference to an abstract element, only element declarations that can substitute the abstract element can be used to validate the instance. + For references to abstract type definitions, only derived types can be used. + + + + + All + All Model Group + + Child elements can be provided + + in any order + + in instances. + + http://www.w3.org/TR/xmlschema-1/#element-all + + + + Choice + Choice Model Group + + + Only one + + from the list of child elements and model groups can be provided in instances. + + http://www.w3.org/TR/xmlschema-1/#element-choice + + + + CollapseWS + Collapse Whitespace Policy + Replace tab, line feed, and carriage return characters with space character (Unicode character 32). Then, collapse contiguous sequences of space characters into single space character, and remove leading and trailing space characters. + + + + ElemBlock + Disallowed Substitutions + + (Applies to element declarations). + If + substitution + is specified, then + + SubGroup + substitution group + + members cannot be used in place of the given element declaration to validate element instances. + + If + derivation methods + , e.g. extension, restriction, are specified, then the given element declaration will not validate element instances that have types derived from the element declaration's type using the specified derivation methods. + Normally, element instances can override their declaration's type by specifying an + xsi:type + attribute. + + + + + Key + Key Constraint + + Like + + Unique + Uniqueness Constraint + + , but additionally requires that the specified value(s) must be provided. + + http://www.w3.org/TR/xmlschema-1/#cIdentity-constraint_Definitions + + + + KeyRef + Key Reference Constraint + + Ensures that the specified value(s) must match value(s) from a + + Key + Key Constraint + + or + + Unique + Uniqueness Constraint + + . + + http://www.w3.org/TR/xmlschema-1/#cIdentity-constraint_Definitions + + + + ModelGroup + Model Group + + Groups together element content, specifying the order in which the element content can occur and the number of times the group of element content may be repeated. + + http://www.w3.org/TR/xmlschema-1/#Model_Groups + + + + Nillable + Nillable + + (Applies to element declarations). + If an element declaration is nillable, instances can use the + xsi:nil + attribute. + The + xsi:nil + attribute is the boolean attribute, + nil + , from the + http://www.w3.org/2001/XMLSchema-instance + namespace. + If an element instance has an + xsi:nil + attribute set to true, it can be left empty, even though its element declaration may have required content. + + + + + Notation + Notation + A notation is used to identify the format of a piece of data. Values of elements and attributes that are of type, NOTATION, must come from the names of declared notations. + http://www.w3.org/TR/xmlschema-1/#cNotation_Declarations + + + + PreserveWS + Preserve Whitespace Policy + Preserve whitespaces exactly as they appear in instances. + + + + TypeFinal + Prohibited Derivations + + (Applies to type definitions). + Derivation methods that cannot be used to create sub-types from a given type definition. + + + + + TypeBlock + Prohibited Substitutions + + (Applies to complex type definitions). + Prevents sub-types that have been derived using the specified derivation methods from validating element instances in place of the given type definition. + + + + + ReplaceWS + Replace Whitespace Policy + Replace tab, line feed, and carriage return characters with space character (Unicode character 32). + + + + Sequence + Sequence Model Group + + Child elements and model groups must be provided + + in the specified order + + in instances. + + http://www.w3.org/TR/xmlschema-1/#element-sequence + + + + SubGroup + Substitution Group + + Elements that are + + members + + of a substitution group can be used wherever the + + head + + element of the substitution group is referenced. + + + + + ElemFinal + Substitution Group Exclusions + + (Applies to element declarations). + Prohibits element declarations from nominating themselves as being able to substitute a given element declaration, if they have types that are derived from the original element's type using the specified derivation methods. + + + + + TargetNS + Target Namespace + The target namespace identifies the namespace that components in this schema belongs to. If no target namespace is provided, then the schema components do not belong to any namespace. + + + + Unique + Uniqueness Constraint + Ensures uniqueness of an element/attribute value, or a combination of values, within a specified scope. + http://www.w3.org/TR/xmlschema-1/#cIdentity-constraint_Definitions + + + + + + + + + + +

    + + + + + + + See: + + + + . + +

    +
    + + + + + + + + +
      + + + +
    +
    + + + true + + + + + + + + +
    +
      + + +
    • + This element can be used wherever the following element is referenced: +
        +
      • + + + +
      • +
      +
    • +
      + + +
    • + The following elements can be used wherever this element is referenced: + +
    • +
      +
    +
    +
    +
    + + + + + + + + + + + + + + +
    + + + Super-types: + + + Parent type: + + + + + + + + + + + None + + +
    + + + Sub-types: + + + Direct sub-types: + + + + + + +
    +
    + + + + + + + + + + + + + + +
    + + + Super-types: + + + Parent type: + + + + + + + + + + + None + + +
    + + + Sub-types: + + + Direct sub-types: + + + + + + +
    +
    + + + + + + + + + + + + + +
  • + + false + + Circular element reference to: + + + +
  • +
    + + + + + + + + + + + + + + + + + + +
  • + + + +
  • + + + + + + + +
    +
    +
    +
    + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Local type definition + + + + + + + + + + + + + + extension + + + restriction + + + + + + restriction + + + + + + + + + + + + < + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + < + + + + + + + + + + + + + + + + + + + (by + + ) + + + + + + + + + + + + + + + + + + + + + (derivation method: + + ) + + + + + + + + + + + true + + + + + + + + + + + +
      + +
    • + + + + + + + (by + + ) + + + + + false + + + +
    • +
      +
    +
    + + + + + + + None + + +
    +
    +
    + + + + + true + + + + + + + + + + + +
      + +
    • + + + + + + + (by restriction) + + + + + false + + + +
    • +
      +
    +
    + + +
      + +
    • + + + + + + + (by + + ) + + + + + false + + + +
    • +
      +
    +
    + + + + true + + + + + true + + + + + + + + + + + + + + None + + +
    +
    +
    + + + + + + + + + + + + + + + + + + +
    + More information at: + + + + . +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    Type + + + Locally-defined simple type + + + + + + + + anySimpleType + + +
    Default Value
    Fixed Value
    +
    + + + + + + + + + + + + + +
    Name
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    + + Abstract + Abstract + + + + + +
    + + TypeFinal + Prohibited Derivations + +
    + + TypeBlock + Prohibited Substitutions + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    Type + + + Locally-defined simple type + + + Locally-defined complex type + + + + + + + + anyType + + +
    + + Nillable + Nillable + + + + + +
    + + Abstract + Abstract + + + + + +
    Default Value
    Fixed Value
    + + ElemFinal + Substitution Group Exclusions + +
    + + ElemBlock + Disallowed Substitutions + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    Public Identifier
    System Identifier
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + TargetNS + Target Namespace + + + + + + + + + + None + + +
    Version
    Language
    Element and Attribute Namespaces +
      +
    • Global element and attribute declarations belong to this schema's target namespace.
    • +
    • + + + By default, local element declarations belong to this schema's target namespace. + + + By default, local element declarations have no namespace. + + +
    • +
    • + + + By default, local attribute declarations belong to this schema's target namespace. + + + By default, local attribute declarations have no namespace. + + +
    • +
    +
    Schema Composition +
      + + +
    • + This schema imports schema(s) from the following namespace(s): +
        + +
      • + + + (at + + + + ) + +
      • +
        +
      +
    • +
      + + +
    • + This schema includes components from the following schema document(s): +
        + +
      • + + + +
      • +
        +
      +
    • +
      + + +
    • + This schema includes components from the following schema document(s), where some of the components have been redefined: +
        + +
      • + + + +
      • +
        +
      + See Redefined Schema Components section. +
    • +
      +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name
    Content + + + +
    + + TypeFinal + Prohibited Derivations + +
    +
    + + + + + + + + + + + Documentation + + +

    + +
    + + +
    + + + Application Data + + +

    + +
    + + +
    +
    + + + + + + + + + + + + + + + + +
    • + List of: + + + + + + + + + +
        +
      • + Locally defined type: + + + + +
      • +
      +
      +
      +
    +
    + + +
    • + Union of following types: +
        + + + + + type + true + + + + +
      • + Locally defined type: + + + + +
      • +
        +
      +
    +
    +
    +
    + + + + + + + + + + + + +
  • + + false + + Circular type reference to ' + + ' in type hierarchy. + + +
  • +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    • + Base XSD Type: + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + +
    • + ' + + ' super type was not found in this schema. + Its facets could not be printed out. +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + +
    • + +
    • +
      + +
    • + +
    • +
      + +
    • + +
    • +
      + +
    • + +
    • +
      + +
    • + +
    • +
      + +
    • + +
    • +
      + +
    • + +
    • +
      +
    +
    +
    + + + + + + + + + + + + + + + + + + + sample + XML Instance Representation + + + + true + + + + + + + 0 + false + false + this + + + + + + Start + + All + All + + + + + + + + + + +
    + + + + + + + + + + + + + End All +
    +
    +
    + + + + 0 + +
    + + + + attribute + element + + + + + + + +
    +
    + + + + + false + false + 0 + false + this + + + + + + + + + + + + + + + + +
    + + + + + newFields + + + inherited + + + + + + + + + + + + + + + =" + + + + + + + + + + + + + + + + + + + + + + + anySimpleType + + + + + + + + + + + + + + + + + " + +
    +
    +
    + + + + + false + false + 0 + false + this + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + newFields + + + inherited + + + + + + + + + =" + + + + + + + + + + + + + + + + + " + +
    +
    +
    + + + + this + + + + + + true + + + false + + + + + + + + + + + + + + + false + false + 0 + + this + + + + + + + + + + + + + false + + Circular attribute group reference: + + + + + + + + + + attribute group + + + + + + +
    + Attribute group reference (not shown): + + + + + + + + +
    +
    + + + + + + + + + + true + + + + + + + + + + + + + true + + + +
    +
    +
    +
    + + + + 0 + false + false + + this + + + + + + Start + + Choice + Choice + + + + + + + + + + +
    + + + + + + + + + + + + + + End Choice +
    +
    +
    + + + + this + + + + + + + + + + + + 0 + false + false + this + + + + + + + + + + + + + + + + + + + + + + + + complex type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + false + false + this + + + + + + + + + + + + + + + this + + + + + + + + + + + + 0 + false + false + + this + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Circular model group reference: + + + + + + + + +
    +
    + + + + + + group + + + + + + +
    + Model group reference (not shown): + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + + + + 0 + false + false + + this + + + + + + + + + + + + + + + Start + + Sequence + Sequence + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + End Sequence +
    +
    +
    +
    + + + + this + + + + + + + + + + + + this + + + + + + + + + + + + 0 + this + +
    + <!--
    + + + + + Unique + Uniqueness + + + + + Key + Key + + + + + KeyRef + Key Reference + + + + Constraint - + + + + + + + + + + + + + + +
    + + Selector - + + +
    + + Field(s) - + + + , + + + + + +
    + + + Refers to - + + + + +
    +
    + + --> +
    +
    + + + + + + + + + + + + + + + true + +A local schema component contains two dashes in +'documentation' elements within its 'annotation' element. + + + + + + , + + ' + + + More information at: + + + + . + + + + + + + + ' + + + + + + + + docArray = new Array( + + ); viewDocumentation(' + + + + ', ' + + + + + + + + + + + ', docArray); + + ? + + + + + + + + + + + + ' + \' + + + + + + " + \" + + + + + + + + 0 + false + false + + + + + + this + + + + + + + Start Group: + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + End Group: + +
    +
    +
    + + + + + 0 + false + false + this + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + newFields + + + inherited + + + + + < + + > + + + + + + + + + + + + + + + + + + + + + + + + + ... + + + + + + + + + + + + + + </ + + > + + + + + + + + + + + + +
    +
    + + + + + + 0 + false + false + this + + + + + + + + + + + + + + + + + + + + + + + + ... + + + + + + + + true + + + false + + + + +
    + + + newFields + + + inherited + + + + + < + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + + + + + + true + + + + + + + + + /> + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + <!-- Restricts : + + + + + --> + +
    + + +
    + <!-- Extends : + + + + + --> + +
    +
    + + + +
    + <!-- Mixed content --> + +
    + + + + + + </ + + > +
    +
    +
    +
    +
    +
    + + + + + + false + false + false + 0 + this + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + false + false + 0 + this + + + + + + + + + + + + + + + + + + + complex type + + + + + + + + + + + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + true + + + false + + + + + + + + + + + + + + + + + + + + + true + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + false + 0 + this + + + + + + + true + + + + + + + + 0 + false + false + false + true + this + + + +
    + + + + + + + + + + + + + + + + + + + complex type + + + + + + +
    + <!-- ' + + + + + ' super type was not found in this schema. Some elements and attributes may be missing. --> +
    +
    + + + + +
    + + + + + + + + + + + true + + + false + + + + + + + + +
    + + + + + + + + + + + + +
    + <-- Extends: + + + + + (Circular type hierarchy) --> +
    +
    + + + + + + complex type + + + + + + + + + + + + + + true + + + false + + + + + + false + + + + + + + +
    + <!-- ' + + + + + ' super type was not found in this schema. Some elements and attributes may be missing. --> +
    +
    + + + + + + + + + + true + + + false + + + + + + false + + + + + +
    + + + + + + + + + + + true + + + false + + + + + + + + +
    +
    +
    + + + + + + + + + +
    +
    + + + + + + + + + + +
    +
    + + + + + + + + + + + + + +
    +
    + + + + + 0 + false + false + this + + + + + + + + + + + + + + + + + + + this + + + + + + + + + + + + + + + + list of: + + + + + + + list of: [ + + + + + ] + + + + + + union of: [ + + + + true + + + + + + type + , + + + + + + , + + [ + + + + + ] + + + ] + + + + + + + + this + + + + + + + + + + false + + Circular type reference to ' + + ' in type hierarchy. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + + + ) + + + ( + + ) + + + ( + + ) + + + ( + + + + ) + + + ( + + + + ) + + + ( + + ) + + + ( + + + + ) + + + + + + + + + + + + + + + + + + schemaComponent + Schema Component Representation + + + + false + + + + + + 0 + + + + + + + + name + + + + + + type + + + + + + + + + + + *name+*type+ + + + *annotation+ + + + + + + 0 + + + + + + + + name + + + + + + *name+ + + + *annotation+ + + + + + + 0 + + + + + + + + ref + + + + + + + + + + *ref+ + + + *annotation+ + + + + + + 0 + + + + + + + + ref + + + + + + + + + + *ref+ + + + *annotation+ + + + + + + 0 + + + + + + + + ref + + + + + + + + + + *ref+ + + + *annotation+ + + + + + + 0 + + + + + + + + ref + + + + + + + + + + *ref+ + + + *annotation+ + + + + + + 0 + + + + + + + + + source + + + + + + + + + + + *source+ + + + true + + + + + + 0 + + + + + + + + name + + + + + refer + + + + + + + + + + + + *name+*refer+ + + + *annotation+ + + + + + + 0 + + + + + + + + + base + + + + + + + + + + + *base+ + + + *annotation+ + + + + + + 0 + + + + + + + + + itemType + + + + + + + + + + + *itemType+ + + + *annotation+ + + + + + + 0 + + + + + + + + + memberTypes + + + + type + + + + + + + + *memberTypes+ + + + *annotation+ + + + + + + 0 + + + + + + + + + xml:lang + + + + + + + *lang+ + + + *include+*import+*redefine+ + + + + + + 0 + + + + + + + + + + *annotation+ + + + + + + 0 + +
    + <-- + + --> +
    +
    + + + + + + 0 + false + + + + + + + + + true + + + + +
    + + < + + + + + + + + + + + + + +
    ...
    +
    + + + + + + + + +
    + +
    +
    + + + + + + +
    +
    + + + + + + > + + + + + + </ + + + + > + + + + + /> + + +
    +
    + + + + + + + + + + + =" + + + + + + " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + html + + + + + + + + + + + + + + xpp + + + + + + + + + + + +
    + <-- + + --> +
    +
    + + + + + xpp + + + < + + + + + + + + + + + + + =" + + " + + + + + + > + + + + + + +
    + +
    +
    +
    + + </ + + + + + + + + + > +
    + + + /> + +
    +
    + + + + + + + + + + + + + + + + + + [term] + + + + + + + + + + + + + + this + + + + + + + + + + + + + + + + + + + Unknown namespace prefix, + + . + + + + + + + + + + + + + + this + + + + + + attribute + + + + + + + attribute + + + + + + + + + + + this + + + + + + attribute group + + + + + + + attribute group + + + + + + + + + + + this + + + + + + element + + + + + + + element + + + + + + + + + + + this + + + + + + group + + + + + + + group + + + + + + + + + + + this + + + + + + uniqueness/key constraint + + + + + + + uniqueness/key constraint + + + + + + + + + + + this + + + + + + + type + + + + + + + + + type + + + + + + + + + + + + + this + + + + + + + declaration + + + definition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "" + + + + + + + Jump to " + + " + + + + + + (located in external schema documentation) + + + + . + + + + + + + + javascript:void(0) + + + + + + + + + + + + + + + externalLink + + + + + + alert(' + + '); + + + + + + + + + + + + this + + + + + + declaration + + + definition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not be found + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xsd + + + + xml + + + + + + + + this + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + false + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + true + + + + false + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + +
    +
    + + + + + + + + + + + + + + + + + + + +
    + + +
    + +
    + + + setState('', ); + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + All Model Group + + + Attribute + + + Attribute Group + + + Choice Model Group + + + Complex Type + + + Element + + + Model Group + + + Notation + + + Sequence Model Group + + + Simple Type + + + + true + +Unknown schema component, . + + + + + + + + + + + + + schema + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + +Unknown schema component, . + + + + + + + + + + + + + Notation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + +Documentation file for the schema at, , +was not specified in the links file, . + + + + + + + + + + + + + + yes + + + no + + + + + + + + false + this + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + + 1 + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + 0 + + + 1 + + + + + + + * + + + + + + + + + 1 + + + + + + + + + + [1] + + + [ + + .. + + ] + + + + + + + + + + + + restriction, extension, substitution + + + + + + + + + + + + + + restriction, extension + + + + + + + + + + + + + + restriction, list, union + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + true + this + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + false + + true + this + + + + + + + + + + + + + + + + + + +
  • + +
  • +
    + + + + + + + + + + + + + + +
    +
    + + + + element + + + + + + Allow any + + s from + + + + + any namespace + + + + a namespace other than this schema's namespace + + + + + + + true + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + no namespace + + + + + + and + + + , + + + this schema's namespace + + + + + + , and + + + and + + + the following namespace(s): + + + , + + + + + + ( + + + + + + strict + + + validation) + . + + + + + + + + + + + + + + + + + pattern + = + + + + + + + + + + total no. of digits + = + + + + + + + + + + + no. of fraction digits + + = + + + + + + + + + + value + comes from list: { + + + + | + + ' + + ' + + + } + + + + + + + + + + + length + + = + + + + + length + + >= + + + + + length + + <= + + + + + + + + + + + + + + Whitespace policy: + + PreserveWS + preserve + + + + Whitespace policy: + + ReplaceWS + replace + + + + Whitespace policy: + + CollapseWS + collapse + + + + + + + + + + + + + + + <= + + + + < + + + + value + + + + <= + + + + < + + + + + + + value + + >= + + + + + value + + > + + + + + value + + <= + + + + + value + + < + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + XS3P ERROR: + + + + + + ERROR: + + + + + + diff --git a/Libs/CommandLineModules/Frontend/QtGui/README.md b/Libs/CommandLineModules/Frontend/QtGui/README.md new file mode 100644 index 0000000000..533302dacc --- /dev/null +++ b/Libs/CommandLineModules/Frontend/QtGui/README.md @@ -0,0 +1,8 @@ +Qt Gui Frontend {#CommandLineModulesFrontendQtGui_Page} +=============== + +The Qt Gui front-end uses a customizable XML stylesheet to transform the raw XML module +description into Qt .ui file. For details about the configuration possibilities of the GUI +generation process see the ctkCmdLineModuleFrontendQtGui class. + +See the \ref CommandLineModulesFrontendQtGui_API module for the API documentation. diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index b29279e310..72192edc52 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -16,6 +16,17 @@ =================================================================== --> + + true QWidget @@ -42,15 +53,9 @@ currentPath currentPath currentPath - text - text - text - text - currentEnumeration - currentEnumeration - currentEnumeration - currentEnumeration - + text + currentEnumeration + - + - true + true - true + true From 1285553cd9fddb9f8096cf42b6019e24821367c8 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 4 Sep 2012 03:55:03 +0200 Subject: [PATCH 190/247] Added a XML schema for progress reports. Added validation test. --- .../Backend/LocalProcess/CMakeLists.txt | 9 ++ .../Resources/ctkCmdLineModuleProcess.xsd | 137 ++++++++++++++++++ .../ctkCmdLineModulesBackendLocalProcess.qrc | 5 + .../ctkCmdLineModuleXmlProgressWatcher.cpp | 17 ++- .../Testing/Cpp/CMakeLists.txt | 8 +- .../ctkCmdLineModuleProcessXmlOutputTest.cpp | 68 +++++++++ .../TestBed/ctkCmdLineModuleTestBed.cpp | 4 +- 7 files changed, 243 insertions(+), 5 deletions(-) create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModuleProcess.xsd create mode 100644 Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModulesBackendLocalProcess.qrc create mode 100644 Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleProcessXmlOutputTest.cpp diff --git a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt index 24df0b3223..f7b76e73aa 100644 --- a/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt +++ b/Libs/CommandLineModules/Backend/LocalProcess/CMakeLists.txt @@ -31,6 +31,7 @@ set(KIT_UI_FORMS # Resources set(KIT_resources + Resources/ctkCmdLineModulesBackendLocalProcess.qrc ) # Target libraries - See CMake/ctkFunctionGetTargetLibraries.cmake @@ -59,6 +60,14 @@ if(CTK_WRAP_PYTHONQT_FULL OR CTK_WRAP_PYTHONQT_LIGHT) ) endif() +find_package(Doxygen) +if(DOXYGEN_FOUND) + # Copy XML schema file to the Doxygen output directory + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/Resources/ctkCmdLineModuleProcess.xsd + ${CTK_BINARY_DIR}/Documentation/html/ctkCmdLineModuleProcess.xsd) +endif() + # Testing if(BUILD_TESTING) #add_subdirectory(Testing) diff --git a/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModuleProcess.xsd b/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModuleProcess.xsd new file mode 100644 index 0000000000..cc60f1da8f --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModuleProcess.xsd @@ -0,0 +1,137 @@ + + + + + + + + CTK XML schema for progress and result reporting in command line modules. + false + false + + The XML schema for the XML fragments used when reporting progress and results in command line modules. + + + + + + + + + The root element. This is added automatically and must not be printed out by the module. + + + + + + + + + + + + + + + + + + + + + Marks the start of a set of processing instructions. + + + + + + The name of the current "filter" (set of processing instructions). + + + + + A short, descriptive text about the purpose of this filter. + + + + + + + + + + A float value between 0 and 1 to report the current overall progress. + + + + + + + + + + + + Report a progress value and corresponding progress text. + + + + + + + + + + Report the current result. + + + + + The output parameter name to which this result belongs to. + + + + + + + + + Marks the end of a set of processing instructions. + + + + + + A short, descriptive text about the end state of this filter. + + + + + + diff --git a/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModulesBackendLocalProcess.qrc b/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModulesBackendLocalProcess.qrc new file mode 100644 index 0000000000..b273f9168f --- /dev/null +++ b/Libs/CommandLineModules/Backend/LocalProcess/Resources/ctkCmdLineModulesBackendLocalProcess.qrc @@ -0,0 +1,5 @@ + + + ctkCmdLineModuleProcess.xsd + + diff --git a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp index 2514e5f588..3ab0f596bf 100644 --- a/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp +++ b/Libs/CommandLineModules/Core/ctkCmdLineModuleXmlProgressWatcher.cpp @@ -33,6 +33,7 @@ static QString FILTER_START = "filter-start"; static QString FILTER_NAME = "filter-name"; static QString FILTER_COMMENT = "filter-comment"; static QString FILTER_PROGRESS = "filter-progress"; +static QString FILTER_PROGRESS_TEXT = "filter-progress-text"; static QString FILTER_RESULT = "filter-result"; static QString FILTER_END = "filter-end"; @@ -91,7 +92,7 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate } if (stack.size() == 2 && - (stack.front() == FILTER_START || stack.front() == FILTER_END || stack.front() == FILTER_PROGRESS)) + (stack.front() == FILTER_START || stack.front() == FILTER_END)) { if (stack.back() == FILTER_NAME) { @@ -106,6 +107,10 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate { currentProgress = reader.text().toString().toFloat(); } + else if (stack.size() == 1 && stack.back() == FILTER_PROGRESS_TEXT) + { + currentComment = reader.text().toString(); + } else if (stack.size() == 1 && stack.back() == FILTER_RESULT) { currentResultValue = reader.text().toString(); @@ -125,6 +130,7 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate if (name.compare(FILTER_START, Qt::CaseInsensitive) == 0 || name.compare(FILTER_PROGRESS, Qt::CaseInsensitive) == 0 || + name.compare(FILTER_PROGRESS_TEXT, Qt::CaseInsensitive) == 0 || name.compare(FILTER_RESULT, Qt::CaseInsensitive) == 0 || name.compare(FILTER_END, Qt::CaseInsensitive) == 0) { @@ -140,6 +146,10 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate currentComment = QString(); currentProgress = 0; } + else if (name.compare(FILTER_PROGRESS_TEXT, Qt::CaseInsensitive) == 0) + { + currentProgress = reader.attributes().value("progress").toString().toFloat(); + } else if (name.compare(FILTER_RESULT, Qt::CaseInsensitive) == 0) { currentResultParameter = reader.attributes().value("name").toString(); @@ -178,6 +188,11 @@ class ctkCmdLineModuleXmlProgressWatcherPrivate emit q->filterProgress(currentProgress, currentComment); currentComment = QString(); } + else if (name.compare(FILTER_PROGRESS_TEXT, Qt::CaseInsensitive) == 0) + { + emit q->filterProgress(currentProgress, currentComment); + currentComment = QString(); + } else if (name.compare(FILTER_RESULT, Qt::CaseInsensitive) == 0) { emit q->filterResult(currentResultParameter, currentResultValue); diff --git a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt index b09f3eabe7..ba61a8e665 100644 --- a/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Testing/Cpp/CMakeLists.txt @@ -9,8 +9,12 @@ if(CTK_LIB_CommandLineModules/Frontend/QtGui) include(${QT_USE_FILE}) if(CTK_LIB_CommandLineModules/Backend/LocalProcess) - list(APPEND _test_srcs ctkCmdLineModuleFutureTest.cpp) - list(APPEND _test_mocs ctkCmdLineModuleFutureTest.cpp) + set(_test_cpp_files + ctkCmdLineModuleFutureTest.cpp + ctkCmdLineModuleProcessXmlOutputTest.cpp + ) + list(APPEND _test_srcs ${_test_cpp_files}) + list(APPEND _test_mocs ${_test_cpp_files}) endif() if(CTK_LIB_CommandLineModules/Backend/FunctionPointer) list(APPEND _test_srcs ctkCmdLineModuleQtCustomizationTest.cpp) diff --git a/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleProcessXmlOutputTest.cpp b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleProcessXmlOutputTest.cpp new file mode 100644 index 0000000000..18a0345659 --- /dev/null +++ b/Libs/CommandLineModules/Testing/Cpp/ctkCmdLineModuleProcessXmlOutputTest.cpp @@ -0,0 +1,68 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + +#include "ctkCmdLineModuleXmlValidator.h" + +#include "ctkTest.h" + +#include +#include +#include + + +//----------------------------------------------------------------------------- +class ctkCmdLineModuleProcessXmlOutputTester : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void testValidXmlOutput(); + +}; + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleProcessXmlOutputTester::testValidXmlOutput() +{ + QString processLocation = QCoreApplication::applicationDirPath() + "/ctkCmdLineModuleTestBed"; + QProcess process; + process.start(processLocation, QStringList() << "--numOutputs" << "1" << "dummy"); + + QVERIFY(process.waitForFinished()); + QByteArray output = process.readAllStandardOutput(); + QVERIFY(!output.isEmpty()); + output.prepend(""); + output.append(""); + + QBuffer buffer(&output); + buffer.open(QIODevice::ReadOnly); + ctkCmdLineModuleXmlValidator xmlValidator(&buffer); + + QFile schema(":/ctkCmdLineModuleProcess.xsd"); + QVERIFY(schema.open(QIODevice::ReadOnly)); + xmlValidator.setInputSchema(&schema); + + QVERIFY(xmlValidator.validateInput()); +} + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleProcessXmlOutputTest) +#include "moc_ctkCmdLineModuleProcessXmlOutputTest.cpp" diff --git a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp index 1f677bed9d..93c5ff8573 100644 --- a/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp +++ b/Libs/CommandLineModules/Testing/Modules/TestBed/ctkCmdLineModuleTestBed.cpp @@ -170,8 +170,8 @@ int main(int argc, char* argv[]) out << output << endl; // report progress - out << "" << (i+1)*progressStep - << "Calculating output " << (i+2) << "..." << endl; + out << QString("").arg((i+1)*progressStep) + << "Calculating output " << (i+2) << "..." << endl; // report the current output number as a result out << "" << (i+1) << "" << endl; } From a39906ce591b903e4948824a99cf79c0644520a9 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 4 Sep 2012 03:55:29 +0200 Subject: [PATCH 191/247] Added test for different module manager validation modes. --- .../Core/Testing/Cpp/CMakeLists.txt | 3 + .../Cpp/ctkCmdLineModuleManagerTest.cpp | 187 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleManagerTest.cpp diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt index 611a629c4a..7bf88c79c1 100644 --- a/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt +++ b/Libs/CommandLineModules/Core/Testing/Cpp/CMakeLists.txt @@ -2,6 +2,7 @@ set(KIT ${PROJECT_NAME}) set(LIBRARY_NAME ${PROJECT_NAME}) create_test_sourcelist(Tests ${KIT}CppTests.cpp + ctkCmdLineModuleManagerTest.cpp ctkCmdLineModuleXmlProgressWatcherTest.cpp ctkCmdLineModuleDefaultPathBuilderTest.cpp ) @@ -24,6 +25,7 @@ include_directories( set(Tests_MOC_CPP) QT4_WRAP_CPP(Tests_MOC_CPP ${Tests_MOC_SRCS}) QT4_GENERATE_MOCS( + ctkCmdLineModuleManagerTest.cpp ctkCmdLineModuleXmlProgressWatcherTest.cpp ) set(Tests_UI_CPP) @@ -39,5 +41,6 @@ target_link_libraries(${KIT}CppTests ${LIBRARY_NAME} ${CTK_BASE_LIBRARIES}) # # Add Tests # +SIMPLE_TEST(ctkCmdLineModuleManagerTest) SIMPLE_TEST(ctkCmdLineModuleXmlProgressWatcherTest) SIMPLE_TEST(ctkCmdLineModuleDefaultPathBuilderTest ${CTK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleManagerTest.cpp b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleManagerTest.cpp new file mode 100644 index 0000000000..b5dc3e5f30 --- /dev/null +++ b/Libs/CommandLineModules/Core/Testing/Cpp/ctkCmdLineModuleManagerTest.cpp @@ -0,0 +1,187 @@ +/*============================================================================= + + Library: CTK + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics + + 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 + + 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. + +=============================================================================*/ + + +#include "ctkCmdLineModuleManager.h" +#include "ctkCmdLineModuleBackend.h" +#include "ctkException.h" +#include "ctkCmdLineModuleFuture.h" + +#include "ctkTest.h" + +#include +#include +#include +#include + +namespace { + +class BackendMockUp : public ctkCmdLineModuleBackend +{ + +public: + + void addModule(const QUrl& location, const QByteArray& xml) + { + this->UrlToXml[location] = xml; + } + + virtual QString name() const { return "Mockup"; } + virtual QString description() const { return "Test Mock-up"; } + virtual QList schemes() const { return QList() << "test"; } + virtual qint64 timeStamp(const QUrl& /*location*/) const { return 0; } + virtual QByteArray rawXmlDescription(const QUrl& location) + { + return UrlToXml[location]; + } + +protected: + + virtual ctkCmdLineModuleFuture run(ctkCmdLineModuleFrontend* /*frontend*/) + { + return ctkCmdLineModuleFuture(); + } + +private: + + QHash UrlToXml; +}; + +} + +//----------------------------------------------------------------------------- +class ctkCmdLineModuleManagerTester : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + + void initTestCase(); + + void testStrictValidation(); + void testWeakValidation(); + void testSkipValidation(); + +private: + + QByteArray validXml; + QByteArray invalidXml; +}; + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleManagerTester::initTestCase() +{ + validXml = "\n" + " My Filter\n" + " Awesome filter\n" + " \n" + " \n" + " bla\n" + " \n" + " param\n" + " i\n" + " bla\n" + " \n" + " \n" + " \n" + "\n"; + + invalidXml = "\n" + " Awesome filter\n" + " My Filter\n" + " \n" + " \n" + " bla\n" + " \n" + " param\n" + " i\n" + " bla\n" + " \n" + " \n" + " \n" + "\n"; +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleManagerTester::testStrictValidation() +{ + BackendMockUp backend; + backend.addModule(QUrl("test://validXml"), validXml); + backend.addModule(QUrl("test://invalidXml"), invalidXml); + + ctkCmdLineModuleManager manager; + manager.registerBackend(&backend); + + ctkCmdLineModuleReference moduleRef = manager.registerModule(QUrl("test://validXml")); + QVERIFY(moduleRef); + QVERIFY(moduleRef.xmlValidationErrorString().isEmpty()); + + try + { + manager.registerModule(QUrl("test://invalidXml")); + QFAIL("Succeeded in registering invalid module"); + } + catch (const ctkInvalidArgumentException&) + { + } +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleManagerTester::testWeakValidation() +{ + BackendMockUp backend; + backend.addModule(QUrl("test://validXml"), validXml); + backend.addModule(QUrl("test://invalidXml"), invalidXml); + + ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::WEAK_VALIDATION); + manager.registerBackend(&backend); + + ctkCmdLineModuleReference moduleRef = manager.registerModule(QUrl("test://validXml")); + QVERIFY(moduleRef); + QVERIFY(moduleRef.xmlValidationErrorString().isEmpty()); + + ctkCmdLineModuleReference moduleRef2 = manager.registerModule(QUrl("test://invalidXml")); + QVERIFY(moduleRef2); + QVERIFY(!moduleRef2.xmlValidationErrorString().isEmpty()); +} + +//----------------------------------------------------------------------------- +void ctkCmdLineModuleManagerTester::testSkipValidation() +{ + BackendMockUp backend; + backend.addModule(QUrl("test://validXml"), validXml); + backend.addModule(QUrl("test://invalidXml"), invalidXml); + + ctkCmdLineModuleManager manager(ctkCmdLineModuleManager::SKIP_VALIDATION); + manager.registerBackend(&backend); + + ctkCmdLineModuleReference moduleRef = manager.registerModule(QUrl("test://validXml")); + QVERIFY(moduleRef); + QVERIFY(moduleRef.xmlValidationErrorString().isEmpty()); + + ctkCmdLineModuleReference moduleRef2 = manager.registerModule(QUrl("test://invalidXml")); + QVERIFY(moduleRef2); + QVERIFY(moduleRef2.xmlValidationErrorString().isEmpty()); +} + +// ---------------------------------------------------------------------------- +CTK_TEST_MAIN(ctkCmdLineModuleManagerTest) +#include "moc_ctkCmdLineModuleManagerTest.cpp" From f2061b629a863ae50fb50e50090d61f3b4a97986 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 4 Sep 2012 04:07:46 +0200 Subject: [PATCH 192/247] Removed extra browse button since ctkPathLineEdit now provides one. --- .../Resources/ctkCmdLineModuleXmlToQtUi.xsl | 132 ++++++------------ 1 file changed, 42 insertions(+), 90 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index 72192edc52..47602fdb41 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -118,21 +118,6 @@ - - - - - BrowseButton - clicked() - parameter: - browse() - - - + @@ -87,8 +90,10 @@ - - + + + + @@ -140,9 +145,16 @@ - - - + + + + + + + + + + @@ -176,7 +188,7 @@ - + @@ -190,7 +202,12 @@ - + + + + + + From 6f1e2e68927a3761669810a73500a06615bdcca9 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sun, 16 Sep 2012 00:32:04 +0100 Subject: [PATCH 242/247] Fixed geometry type to have geometryInputValueProperty and geometryOutputValueProperty --- .../Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index bee73801f1..a118919e88 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -54,7 +54,8 @@ currentPath currentPath currentPath - currentPath + currentPath + currentPath text currentEnumeration @@ -95,7 +96,8 @@ - + + From 3e084112340a6999930851ed09b83bc9b8afe2c4 Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sun, 16 Sep 2012 00:40:01 +0100 Subject: [PATCH 243/247] Updated doygen in ctkCmdLineModuleFrontendQtGui for new Input/Output ValueProperty fields --- .../Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h index 374aaeffbe..4f321aa182 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h +++ b/Libs/CommandLineModules/Frontend/QtGui/ctkCmdLineModuleFrontendQtGui.h @@ -81,15 +81,15 @@ struct ctkCmdLineModuleFrontendQtGuiPrivate; * float-enumerationenumWidgetQComboBoxenumerationValuePropertycurrentEnumeration * double-enumerationenumWidgetQComboBoxenumerationValuePropertycurrentEnumeration * string-enumerationenumWidgetQComboBoxenumerationValuePropertycurrentEnumeration - * file (input channel)fileInputWidgetctkPathLineEditfileValuePropertycurrentPath - * file (output channel)fileOutputWidgetctkPathLineEditfileValuePropertycurrentPath - * geometry (input channel)fileInputWidgetctkPathLineEditfileValuePropertycurrentPath - * geometry (output channel)fileOutputWidgetctkPathLineEditfileValuePropertycurrentPath + * file (input channel)fileInputWidgetctkPathLineEditfileInputValuePropertycurrentPath + * file (output channel)fileOutputWidgetctkPathLineEditfileOutputValuePropertycurrentPath + * geometry (input channel)fileInputWidgetctkPathLineEditgeometryInputValuePropertycurrentPath + * geometry (output channel)fileOutputWidgetctkPathLineEditgeometryOutputValuePropertycurrentPath * directorydirectoryWidgetctkPathLineEditdirectoryValuePropertycurrentPath * pointpointWidgetctkCoordinatesWidgetpointValuePropertycoordinates * regionpointWidgetctkCoordinatesWidgetpointValuePropertycoordinates - * image (input channel)imageInputWidgetctkPathLineEditimageValuePropertycurrentPath - * image (output channel)imageOutputWidgetctkPathLineEditimageValuePropertycurrentPath + * image (input channel)imageInputWidgetctkPathLineEditimageInputValuePropertycurrentPath + * image (output channel)imageOutputWidgetctkPathLineEditimageOutputValuePropertycurrentPath * [main container]executableWidgetQWidgetn/an/a * [group container]parametersWidgetctkCollapsibleGroupBoxn/an/a * [unknown type]unsupportedWidgetQLabeln/an/a From b3cdb0dd5ab0a9f37802f677e7e5ad83ef994bfc Mon Sep 17 00:00:00 2001 From: MattClarkson Date: Sun, 16 Sep 2012 01:15:38 +0100 Subject: [PATCH 244/247] Fix ctkCmdLineModuleXmlToQtUi.xsl for when channel tag does not exist --- .../Resources/ctkCmdLineModuleXmlToQtUi.xsl | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl index a118919e88..5d1a60d504 100644 --- a/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl +++ b/Libs/CommandLineModules/Frontend/QtGui/Resources/ctkCmdLineModuleXmlToQtUi.xsl @@ -147,16 +147,25 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -204,14 +213,20 @@ - - - - - - - - + + + + + + + + + + + + + + From 9854d312701528bf7d854408672ad94fadc507f1 Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Mon, 17 Sep 2012 17:03:58 +0200 Subject: [PATCH 245/247] #237 Added SizeAdjustPolicy property to control the resizing behavior. --- Libs/Widgets/ctkPathLineEdit.cpp | 180 ++++++++++++++++++++++--------- Libs/Widgets/ctkPathLineEdit.h | 35 +++++- 2 files changed, 160 insertions(+), 55 deletions(-) diff --git a/Libs/Widgets/ctkPathLineEdit.cpp b/Libs/Widgets/ctkPathLineEdit.cpp index 03a6bdbe4d..bc29500914 100644 --- a/Libs/Widgets/ctkPathLineEdit.cpp +++ b/Libs/Widgets/ctkPathLineEdit.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // CTK includes #include "ctkPathLineEdit.h" @@ -47,9 +48,11 @@ class ctkPathLineEditPrivate public: ctkPathLineEditPrivate(ctkPathLineEdit& object); void init(); - QSize sizeHint(const QString& text)const; + QSize recomputeSizeHint(QSize& sh)const; void updateFilter(); + void adjustPathLineEditSize(); + void createPathLineEditWidget(bool useComboBox); QString settingKey()const; @@ -73,6 +76,11 @@ class ctkPathLineEditPrivate static QString sCurrentDirectory; //!< Content the last value of the current directory static int sMaxHistory; //!< Size of the history, if the history is full and a new value is added, the oldest value is dropped + + ctkPathLineEdit::SizeAdjustPolicy SizeAdjustPolicy; + + mutable QSize SizeHint; + mutable QSize MinimumSizeHint; }; QString ctkPathLineEditPrivate::sCurrentDirectory = ""; @@ -80,14 +88,15 @@ int ctkPathLineEditPrivate::sMaxHistory = 5; //----------------------------------------------------------------------------- ctkPathLineEditPrivate::ctkPathLineEditPrivate(ctkPathLineEdit& object) - :q_ptr(&object) + : q_ptr(&object) + , LineEdit(0) + , ComboBox(0) + , BrowseButton(0) + , MinimumContentsLength(0) + , Filters(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Readable) + , HasValidInput(false) + , SizeAdjustPolicy(ctkPathLineEdit::AdjustToContentsOnFirstShow) { - this->LineEdit = 0; - this->ComboBox = 0; - this->BrowseButton = 0; - this->MinimumContentsLength = 17; - this->HasValidInput = false; - this->Filters = QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Readable; } //----------------------------------------------------------------------------- @@ -158,42 +167,75 @@ void ctkPathLineEditPrivate::createPathLineEditWidget(bool useComboBox) } //------------------------------------------------------------------------------ -QSize ctkPathLineEditPrivate::sizeHint(const QString& text)const +QSize ctkPathLineEditPrivate::recomputeSizeHint(QSize& sh)const { Q_Q(const ctkPathLineEdit); - int frame = 0; - if (this->ComboBox) + if (!sh.isValid()) { - QStyleOptionComboBox option; - int arrowWidth = this->ComboBox->style()->subControlRect( - QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, this->ComboBox).width() - + (this->ComboBox->hasFrame() ? 2 : 0); - frame = 2 * (this->ComboBox->hasFrame() ? 3 : 0) - + arrowWidth - + 1; // for mac style, not sure why + int frame = 0; + if (this->ComboBox) + { + QStyleOptionComboBox option; + int arrowWidth = this->ComboBox->style()->subControlRect( + QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, this->ComboBox).width() + + (this->ComboBox->hasFrame() ? 2 : 0); + frame = 2 * (this->ComboBox->hasFrame() ? 3 : 0) + + arrowWidth + + 1; // for mac style, not sure why } - else + else { - QStyleOptionFrame option; - int frameWidth = this->LineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q); - int horizontalMargin = 2; // QLineEditPrivate::horizontalMargin - // See QLineEdit::sizeHint - frame = 2 * frameWidth - + this->LineEdit->textMargins().left() - + this->LineEdit->textMargins().right() - + this->LineEdit->contentsMargins().left() - + this->LineEdit->contentsMargins().right() - + 2 * horizontalMargin; + QStyleOptionFrame option; + int frameWidth = this->LineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q); + int horizontalMargin = 2; // QLineEditPrivate::horizontalMargin + // See QLineEdit::sizeHint + frame = 2 * frameWidth + + this->LineEdit->textMargins().left() + + this->LineEdit->textMargins().right() + + this->LineEdit->contentsMargins().left() + + this->LineEdit->contentsMargins().right() + + 2 * horizontalMargin; } - int browseWidth = 0; - if (q->showBrowseButton()) + int browseWidth = 0; + if (q->showBrowseButton()) { - browseWidth = this->BrowseButton->minimumSizeHint().width(); + browseWidth = this->BrowseButton->minimumSizeHint().width(); } - int textWidth = this->LineEdit->fontMetrics().width(text); - int height = (this->ComboBox ? this->ComboBox->minimumSizeHint() : - this->LineEdit->minimumSizeHint()).height(); - return QSize(frame + textWidth + browseWidth, height); + + // text width + int textWidth = 0; + if (&sh == &SizeHint || MinimumContentsLength == 0) + { + switch (SizeAdjustPolicy) + { + case ctkPathLineEdit::AdjustToContents: + case ctkPathLineEdit::AdjustToContentsOnFirstShow: + if (this->LineEdit->text().isEmpty()) + { + textWidth = 7 * this->LineEdit->fontMetrics().width(QLatin1Char('x')); + } + else + { + textWidth = this->LineEdit->fontMetrics().boundingRect(this->LineEdit->text()).width() + 8; + } + break; + case QComboBox::AdjustToMinimumContentsLength: + default: + ; + } + } + + if (MinimumContentsLength > 0) + { + textWidth = qMax(textWidth, MinimumContentsLength * this->LineEdit->fontMetrics().width(QLatin1Char('X'))); + } + + int height = (this->ComboBox ? this->ComboBox->minimumSizeHint() : + this->LineEdit->minimumSizeHint()).height(); + sh.rwidth() = frame + textWidth + browseWidth; + sh.rheight() = height; + } + return sh.expandedTo(QApplication::globalStrut()); } //----------------------------------------------------------------------------- @@ -214,6 +256,18 @@ void ctkPathLineEditPrivate::updateFilter() this->LineEdit->setValidator(validator); } +//----------------------------------------------------------------------------- +void ctkPathLineEditPrivate::adjustPathLineEditSize() +{ + Q_Q(ctkPathLineEdit); + if (q->sizeAdjustPolicy() == ctkPathLineEdit::AdjustToContents) + { + q->updateGeometry(); + q->adjustSize(); + q->update(); + } +} + //----------------------------------------------------------------------------- QString ctkPathLineEditPrivate::settingKey()const { @@ -509,7 +563,13 @@ void ctkPathLineEdit::updateHasValidInput() { emit validInputChanged(d->HasValidInput); } - this->updateGeometry(); + + if (d->SizeAdjustPolicy == AdjustToContents) + { + d->SizeHint = QSize(); + d->adjustPathLineEditSize(); + this->updateGeometry(); + } } //------------------------------------------------------------------------------ @@ -555,6 +615,26 @@ void ctkPathLineEdit::setShowHistoryButton(bool visible) d->createPathLineEditWidget(visible); } +//------------------------------------------------------------------------------ +ctkPathLineEdit::SizeAdjustPolicy ctkPathLineEdit::sizeAdjustPolicy() const +{ + Q_D(const ctkPathLineEdit); + return d->SizeAdjustPolicy; +} + +//------------------------------------------------------------------------------ +void ctkPathLineEdit::setSizeAdjustPolicy(ctkPathLineEdit::SizeAdjustPolicy policy) +{ + Q_D(ctkPathLineEdit); + if (policy == d->SizeAdjustPolicy) + return; + + d->SizeAdjustPolicy = policy; + d->SizeHint = QSize(); + d->adjustPathLineEditSize(); + updateGeometry(); +} + //------------------------------------------------------------------------------ int ctkPathLineEdit::minimumContentsLength()const { @@ -566,31 +646,29 @@ int ctkPathLineEdit::minimumContentsLength()const void ctkPathLineEdit::setMinimumContentsLength(int length) { Q_D(ctkPathLineEdit); + if (d->MinimumContentsLength == length || length < 0) return; + d->MinimumContentsLength = length; - this->updateGeometry(); + + if (d->SizeAdjustPolicy == AdjustToContents || + d->SizeAdjustPolicy == AdjustToMinimumContentsLength) + { + d->SizeHint = QSize(); + d->adjustPathLineEditSize(); + this->updateGeometry(); + } } //------------------------------------------------------------------------------ QSize ctkPathLineEdit::minimumSizeHint()const { Q_D(const ctkPathLineEdit); - QString fileName = QString('/') + QFileInfo(this->currentPath()).fileName(); - if (fileName.size() < d->MinimumContentsLength) - { - fileName = QString("x").repeated(d->MinimumContentsLength); - } - QSize hint = d->sizeHint(fileName); - return hint; + return d->recomputeSizeHint(d->MinimumSizeHint); } //------------------------------------------------------------------------------ QSize ctkPathLineEdit::sizeHint()const { Q_D(const ctkPathLineEdit); - QString path = this->currentPath(); - if (path.size() < d->MinimumContentsLength) - { - path = QString("x").repeated(d->MinimumContentsLength); - } - return d->sizeHint(path); + return d->recomputeSizeHint(d->SizeHint); } diff --git a/Libs/Widgets/ctkPathLineEdit.h b/Libs/Widgets/ctkPathLineEdit.h index e5f0823c80..930e362e81 100644 --- a/Libs/Widgets/ctkPathLineEdit.h +++ b/Libs/Widgets/ctkPathLineEdit.h @@ -74,7 +74,7 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget Q_PROPERTY(QFileDialog::Options options READ options WRITE setOptions) #else Q_PROPERTY(Options options READ options WRITE setOptions) - Q_FLAGS(Option Options); + Q_FLAGS(Option Options) #endif /// This property controls the key used to search the settings for recorded @@ -91,17 +91,23 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget /// not. Clicking on the button calls opens a dialog to select the current path. /// True by default /// \sa browse() - Q_PROPERTY(bool showBrowseButton READ showBrowseButton WRITE setShowBrowseButton); + Q_PROPERTY(bool showBrowseButton READ showBrowseButton WRITE setShowBrowseButton) /// This property controls whether the history button (arrow button that opens /// the history menu) is visible or not. /// True by default. /// \sa retrieveHistory(), addCurrentPathToHistory(), settingKey - Q_PROPERTY(bool showHistoryButton READ showHistoryButton WRITE setShowHistoryButton); + Q_PROPERTY(bool showHistoryButton READ showHistoryButton WRITE setShowHistoryButton) + + /// This property holds the policy describing how the size of the path line edit widget + /// changes when the content changes. + /// The default value is AdjustToContentsOnFirstShow. + Q_PROPERTY(SizeAdjustPolicy sizeAdjustPolicy READ sizeAdjustPolicy WRITE setSizeAdjustPolicy) /// This property holds the minimum number of characters that should fit into /// the path line edit. - /// The default value is 17. + /// The default value is 0. + /// If this property is set to a positive value, the minimumSizeHint() and sizeHint() take it into account. Q_PROPERTY(int minimumContentsLength READ minimumContentsLength WRITE setMinimumContentsLength) public: @@ -143,6 +149,17 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget Q_DECLARE_FLAGS(Options, Option) #endif + enum SizeAdjustPolicy + { + /// The path line edit will always adjust to the contents. + AdjustToContents, + /// The path line edit will adjust to its contents the first time it is shown. + AdjustToContentsOnFirstShow, + /// The combobox will adjust to minimumContentsLength. For performance reasons + /// use this policy on large models. + AdjustToMinimumContentsLength + }; + /** Default constructor */ ctkPathLineEdit(QWidget *parent = 0); @@ -192,6 +209,16 @@ class CTK_WIDGETS_EXPORT ctkPathLineEdit: public QWidget bool showHistoryButton()const; void setShowHistoryButton(bool visible); + /// the policy describing how the size of the combobox changes + /// when the content changes + /// + /// The default value is \c AdjustToContentsOnFirstShow. + /// + /// \sa SizeAdjustPolicy + SizeAdjustPolicy sizeAdjustPolicy() const; + + void setSizeAdjustPolicy(SizeAdjustPolicy policy); + int minimumContentsLength()const; void setMinimumContentsLength(int lenght); From b7e91aeb25006af16463ddeff4d29dda6f0504ed Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 18 Sep 2012 00:38:36 +0200 Subject: [PATCH 246/247] #237 Fixed some coding style issues. --- Libs/Widgets/ctkPathLineEdit.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Libs/Widgets/ctkPathLineEdit.cpp b/Libs/Widgets/ctkPathLineEdit.cpp index bc29500914..539e3b35d3 100644 --- a/Libs/Widgets/ctkPathLineEdit.cpp +++ b/Libs/Widgets/ctkPathLineEdit.cpp @@ -61,6 +61,7 @@ class ctkPathLineEditPrivate QToolButton* BrowseButton; //!< "..." button int MinimumContentsLength; + ctkPathLineEdit::SizeAdjustPolicy SizeAdjustPolicy; QString Label; //!< used in file dialogs QStringList NameFilters; //!< Regular expression (in wildcard mode) used to help the user to complete the line @@ -77,8 +78,6 @@ class ctkPathLineEditPrivate static QString sCurrentDirectory; //!< Content the last value of the current directory static int sMaxHistory; //!< Size of the history, if the history is full and a new value is added, the oldest value is dropped - ctkPathLineEdit::SizeAdjustPolicy SizeAdjustPolicy; - mutable QSize SizeHint; mutable QSize MinimumSizeHint; }; @@ -93,9 +92,9 @@ ctkPathLineEditPrivate::ctkPathLineEditPrivate(ctkPathLineEdit& object) , ComboBox(0) , BrowseButton(0) , MinimumContentsLength(0) + , SizeAdjustPolicy(ctkPathLineEdit::AdjustToContentsOnFirstShow) , Filters(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Readable) , HasValidInput(false) - , SizeAdjustPolicy(ctkPathLineEdit::AdjustToContentsOnFirstShow) { } @@ -174,7 +173,7 @@ QSize ctkPathLineEditPrivate::recomputeSizeHint(QSize& sh)const { int frame = 0; if (this->ComboBox) - { + { QStyleOptionComboBox option; int arrowWidth = this->ComboBox->style()->subControlRect( QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, this->ComboBox).width() @@ -182,9 +181,9 @@ QSize ctkPathLineEditPrivate::recomputeSizeHint(QSize& sh)const frame = 2 * (this->ComboBox->hasFrame() ? 3 : 0) + arrowWidth + 1; // for mac style, not sure why - } + } else - { + { QStyleOptionFrame option; int frameWidth = this->LineEdit->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q); int horizontalMargin = 2; // QLineEditPrivate::horizontalMargin @@ -195,16 +194,16 @@ QSize ctkPathLineEditPrivate::recomputeSizeHint(QSize& sh)const + this->LineEdit->contentsMargins().left() + this->LineEdit->contentsMargins().right() + 2 * horizontalMargin; - } + } int browseWidth = 0; if (q->showBrowseButton()) - { + { browseWidth = this->BrowseButton->minimumSizeHint().width(); - } + } // text width int textWidth = 0; - if (&sh == &SizeHint || MinimumContentsLength == 0) + if (&sh == &this->SizeHint || this->MinimumContentsLength == 0) { switch (SizeAdjustPolicy) { @@ -225,9 +224,9 @@ QSize ctkPathLineEditPrivate::recomputeSizeHint(QSize& sh)const } } - if (MinimumContentsLength > 0) + if (this->MinimumContentsLength > 0) { - textWidth = qMax(textWidth, MinimumContentsLength * this->LineEdit->fontMetrics().width(QLatin1Char('X'))); + textWidth = qMax(textWidth, this->MinimumContentsLength * this->LineEdit->fontMetrics().width(QLatin1Char('X'))); } int height = (this->ComboBox ? this->ComboBox->minimumSizeHint() : @@ -632,7 +631,7 @@ void ctkPathLineEdit::setSizeAdjustPolicy(ctkPathLineEdit::SizeAdjustPolicy poli d->SizeAdjustPolicy = policy; d->SizeHint = QSize(); d->adjustPathLineEditSize(); - updateGeometry(); + this->updateGeometry(); } //------------------------------------------------------------------------------ @@ -652,11 +651,11 @@ void ctkPathLineEdit::setMinimumContentsLength(int length) if (d->SizeAdjustPolicy == AdjustToContents || d->SizeAdjustPolicy == AdjustToMinimumContentsLength) - { + { d->SizeHint = QSize(); d->adjustPathLineEditSize(); this->updateGeometry(); - } + } } //------------------------------------------------------------------------------ From bcc2c48b47a1d31c97b3cbb2354e1d22b22b3f3d Mon Sep 17 00:00:00 2001 From: Sascha Zelzer Date: Tue, 18 Sep 2012 00:38:51 +0200 Subject: [PATCH 247/247] #237 Adjust the with of the completer popup to show complete filenames. --- Libs/Widgets/CMakeLists.txt | 2 +- Libs/Widgets/ctkPathLineEdit.cpp | 41 +++++++++++++++++++++++++++++++- Libs/Widgets/ctkPathLineEdit.h | 2 ++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/Libs/Widgets/CMakeLists.txt b/Libs/Widgets/CMakeLists.txt index 2b92262a05..ba9965bc3e 100644 --- a/Libs/Widgets/CMakeLists.txt +++ b/Libs/Widgets/CMakeLists.txt @@ -230,7 +230,6 @@ set(KIT_MOC_SRCS ctkMenuComboBox_p.h ctkMessageBox.h ctkModalityWidget.h - ctkPathLineEdit.h ctkPathListButtonsWidget.h ctkPathListButtonsWidget_p.h ctkPopupWidget.h @@ -269,6 +268,7 @@ set(KIT_MOC_SRCS ) QT4_GENERATE_MOCS( + ctkPathLineEdit.h ctkPathListWidget.h ) diff --git a/Libs/Widgets/ctkPathLineEdit.cpp b/Libs/Widgets/ctkPathLineEdit.cpp index 539e3b35d3..edfde3fc8e 100644 --- a/Libs/Widgets/ctkPathLineEdit.cpp +++ b/Libs/Widgets/ctkPathLineEdit.cpp @@ -19,6 +19,8 @@ =========================================================================*/ // Qt includes +#include +#include #include #include #include @@ -31,7 +33,6 @@ #include #include #include -#include // CTK includes #include "ctkPathLineEdit.h" @@ -53,6 +54,8 @@ class ctkPathLineEditPrivate void adjustPathLineEditSize(); + void _q_recomputeCompleterPopupSize(); + void createPathLineEditWidget(bool useComboBox); QString settingKey()const; @@ -249,6 +252,9 @@ void ctkPathLineEditPrivate::updateFilter() QDir::Name|QDir::DirsLast, newCompleter)); this->LineEdit->setCompleter(newCompleter); + QObject::connect(this->LineEdit->completer()->completionModel(), SIGNAL(layoutChanged()), + q, SLOT(_q_recomputeCompleterPopupSize())); + // don't accept invalid path QRegExpValidator* validator = new QRegExpValidator( ctk::nameFiltersToRegExp(this->NameFilters), q); @@ -267,6 +273,37 @@ void ctkPathLineEditPrivate::adjustPathLineEditSize() } } +//----------------------------------------------------------------------------- +void ctkPathLineEditPrivate::_q_recomputeCompleterPopupSize() +{ + QSize lineEditSize = this->LineEdit->size(); + + QAbstractItemView* view = this->LineEdit->completer()->popup(); + const QFontMetrics& fm = view->fontMetrics(); + + int iconWidth = 0; + int textWidth = 0; + + QStyleOptionFrame option; + int frameWidth = view->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, view); + int frame = 2 * frameWidth + + view->contentsMargins().left() + + view->contentsMargins().right(); + + QAbstractItemModel* model = this->LineEdit->completer()->completionModel(); + for (int i = 0; i < model->rowCount(); ++i) + { + QVariant icon = model->data(model->index(i, 0), Qt::DecorationRole); + if (icon.isValid() && icon.canConvert()) + { + iconWidth = qMax(iconWidth, icon.value().availableSizes().front().width() + 4); + } + textWidth = qMax(textWidth, fm.boundingRect(model->data(model->index(i, 0)).toString()).width()); + } + + view->setMinimumWidth(qMax(frame + iconWidth + textWidth, lineEditSize.width())); +} + //----------------------------------------------------------------------------- QString ctkPathLineEditPrivate::settingKey()const { @@ -671,3 +708,5 @@ QSize ctkPathLineEdit::sizeHint()const Q_D(const ctkPathLineEdit); return d->recomputeSizeHint(d->SizeHint); } + +#include "moc_ctkPathLineEdit.h" diff --git a/Libs/Widgets/ctkPathLineEdit.h b/Libs/Widgets/ctkPathLineEdit.h index 930e362e81..aa5663beaa 100644 --- a/Libs/Widgets/ctkPathLineEdit.h +++ b/Libs/Widgets/ctkPathLineEdit.h @@ -271,6 +271,8 @@ protected Q_SLOTS: private: Q_DECLARE_PRIVATE(ctkPathLineEdit); Q_DISABLE_COPY(ctkPathLineEdit); + + Q_PRIVATE_SLOT(d_ptr, void _q_recomputeCompleterPopupSize()) }; Q_DECLARE_OPERATORS_FOR_FLAGS(ctkPathLineEdit::Filters)