diff --git a/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox b/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox index 4e0992f1a5..e1481463fb 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Concepts/TestsGeneral.dox @@ -1,93 +1,104 @@ /** \page GeneralTests General: Tests in MITK -Two types of standardizes automated tests are provided by MITK. These types are unit tests and rendering tests . This section will describe unit testing in MITK, while more information on rendering tests can be found in the section \ref RenderingTests. +\tableofcontents --# \ref GeneralTestsSection1 "Basic Information on Unit Testing" --# \ref GeneralTestsSection2 "Adding a Unit Test to MITK" - -# \ref GeneralTestsSection2_1 "Structure your test method" --# \ref GeneralTestsSection3 "Run a Unit Test with MITK" --# \ref GeneralTestsSection4 "MITK Testing Macros" +\section GeneralTestsIntroduction Testing in MITK -\section GeneralTestsSection1 Basic Information on Unit Testing +The basic idea about unit testing is to write a test for every unit (e.g. function) of your software, which automatically checks if the code still returns the expected result for a defined input. The goal is to isolate units as much as possible, in order to be efficient with fixing errors. -The basic idea about unit testing is to write a test for every class (unit) of your software. The test should then run all methods of the tested class and check if the results are correct. Thus, the testing environment for MITK allows for simple implementation of corresponding test methods for MITK classes. +If this is performed on a low level, this is called unit testing. On higher levels, where various circumstances (such as configuration files, internet connection, hardware, or even input/output) may influence the outcome of the test, this is called integration testing. -The build system of MITK generates a test driver which includes all tests that have been added to the project. Alternativly you can run MITK tests by using the program ctest. This is the way all MITK tests run on the continous dart clients of MITK. The results of these runs can be found at http://cdash.mitk.org. +MITK uses CppUnit, which is a framework for efficient and fast test writing, to support developers in test coding. Furthermore MITK offers currently three types of tests: classic unit tests, rendering tests and interaction tests. Although our unit tests often involve data input (or output), we still consider them to be unit tests. -The following sections will explain how to write your own tests with MITK and how to run them. The last section will describe the testing macros of MITK in detail. +\warning Most of our units tests have been written before adopting CppUnit and have not yet been updated. Therefore we do not recommend to look at a random test for an example of coding a test. -\section GeneralTestsSection2 Adding a Unit Test to MITK +This pages gives a general introduction to our test framework. Rendering tests are explained in more detail in the section \ref RenderingTests and interaction tests the section \ref InteractionTestingHowTo. The following sections will explain how to write your own tests with MITK and how to run them. -To add a test, you simply need to create a new file "mitkMyTest.cpp" in the folder "Testing" of the software module to which you want to add the test. The file must contain such a method: \code int mitkMyTest(int argc, char* argv[]) \endcode This method is automatically called by the test driver. A header file to this cpp file is not needed. An example for a simple test method is shown next. +\section GeneralTestsAdding Adding a test to your module +Generally, functional code you want to test using unit tests will be located in a module. For an overview of the directory structure see \ref NewModulePageCreateFolder and how to add the files comprising your test compare \ref NewModulePageCreateTestingEnvironment + +\subsection GeneralTestsAddingFramework Test and test class/suite + +CppUnit and MITK distinguish between the term test class and test, which is important to understand. A test is simply a call of a single function and a comparison against a reference. + +The ideal way to write a test is: \code -int mitkMyTest(int argc, char* argv[]) -{ - MITK_TEST_BEGIN("MyTest"); - MITK_TEST_CONDITION_REQUIRED(true,"Here we test our condition"); - MITK_TEST_END(); -} + result = myGreatFunction(myParameter); + ASSERT_EQUAL(result, reference); \endcode -Additionaly you've to add the test file to the files.cmake of your testing directory. In the files.cmake you'll find a command "SET(MODULE_TESTS [...])", this is where you've to add the filename of your test. This will add your test to the test driver. A possible files.cmake where a test have already been added is shown next. +which is just 2 lines of code at the best. Sometimes objects and data may be initialized in a test, but usually this should be done in the setUp() method (see below). If possible, avoid multiple assertions in order to be efficient in error localization and for better readability. For instance, if you instantiate an object and test if its data is not NULL, this is already a complete test and you do not want to repeat this comparison in other tests. + +All tests check different things and just one at a time. Remember: The goal is to have isolated unit tests and avoid large, confusing tests which are hard to maintain. +\note The reference should never be computed and ideally be a distinct and well defined (often hard coded) value. You don't care where you reference comes from, you just want to ensure that your test actually results in the reference value. + +A test class (also called suite) is a set of tests and often associated to a single functional class in MITK. A test class refers to a TestSuite in CppUnit. These terms are easily confused, so we suggest to use the term test suite for a collection of tests (which is often in a single file), and the term "test" for a single test (usually many per file). + +In order to create a test class you need to create a new class deriving from mitk::TestFixture. While a purist approach would be to create a new mitk::TestFixture for each method of your class (resulting in as many test source files as your class has methods), we usually follow a more pragmatic approach within MITK. In most cases we suggest having one test source file per class. If your class source file is called mitkGreatClass.cpp we suggest the name mitkGreatClassTest.cpp for your test source file. For very complex and long classes splitting this into several tests may be advisable. Additionally, rendering tests and interaction tests should always get their own test class/suite to mark them as obvious integration tests, because the goal is to isolate unit tests from integration tests. The dashboard for continuous integration will automatically show the results of a test suite and summarize the output. If you run your test manually (e.g. with ctest -VV), you will see the detailed output of all tests of the suite. + +In order to use CppUnit via MITK you will need to include the corresponding files and register your test: \code -SET(MODULE_TESTS - mitkMyTest.cpp - [...] -) + #include + #include + … + MITK_TEST_SUITE_REGISTRATION(mitkImageEqual) \endcode -Finally you only have to run cmake one your project and then compile the test driver. Don't forget to turn "BUILD_TESTING" on, when running cmake. -\subsection GeneralTestsSection2_1 Structure your test method +\subsection GeneralTestsAddingHow How to structure your test -When implementing more complex test methods you might want to structure them, e.g. by using sub methods. This is also possible. You can create a test class and add static methods which can then be called in your main test method. This is a simple way to keep a clear structure in your test file. An example for such a structured test file is shown next. +As mentioned before, all test suites derive from mitk::TestFixture. A suggested name for your test suite would be TestSuite. +You then create a suite and register your tests. A suggested naming convention for test methods is __. We suggest not to add the word test, because that is most likely the only thing the reader knows anyway about your test, as he is reading a test suite. + +An example: \code -//first: your test class with static methods, if it comes before the main test method -// like shown here, you still don't need a header and you can keep your code as -// simple as possible -class mitkMyTestClass -{ -public: - - static void TestInstantiation() + class mitkImageEqualTestSuite : public mitk::TestFixture { - //do your instantiation test here + CPPUNIT_TEST_SUITE(mitkImageEqualTestSuite); + MITK_TEST(Equal_CloneAndOriginal_ReturnsTrue); + MITK_TEST(Equal_InputIsNull_ReturnsFalse); + MITK_TEST(Equal_DifferentImageGeometry_ReturnsFalse); + MITK_TEST(Equal_DifferentPixelTypes_ReturnsFalse); + … + CPPUNIT_TEST_SUITE_END(); + … } - - static void TestMethod1() - { - //do a test of method 1 here - } -};//do not forget the semicolon at this place! - -//secondly: your main test method -int mitkMyTest(int argc, char* argv[]) -{ - MITK_TEST_BEGIN("MyTest"); - mitkMyTestClass.TestInstantiation(); - mitkMyTestClass.TestMethod1(); - MITK_TEST_END(); -} \endcode -\section GeneralTestsSection3 Run a Unit Test with MITK +You also may provide a setUp() and a tearDown() function. These will be called before/after each test and should be used to make sure that each test works independently and on freshly initialized members and memory to maximize isolation. That way you avoid only testing whether a function works after another function has already been called. See CppUnit documentation for more information. For an example test suite including tests see \ref GeneralTestsExample + +\section GeneralTestsRunning Running your test suite + +The build system of MITK generates a test driver which includes all test suites that have been added to the project. Alternatively you can run MITK test suites by using the program ctest. This is the way all MITK tests run on the continuous dart clients of MITK. The results of these runs can be found at http://cdash.mitk.org. + +If you use the test driver, you only need to start the executable. If you start it without parameters, it will then give you an overview of all tests which are included in this test driver and you can choose one by typing a number. Alternatively, you can give your test driver the name of your test suite as parameter. If you want to use ctest instead of the test driver you need to start a command line, go to the binary directory of MITK and call ctest. To avoid errors, check if your path variable contains all relevant paths to start MITK. -After building and compiling MITK, there are two ways to run your test. Firstly, you can run your test using the executable test driver. Secondly, you can use the external program ctest. +\section GeneralTestsParameterInput Adding parameters to your test -If you use the test driver, you only need to start the executable. If you start it without parameters, it will then give you an overview of all tests which are included in this test driver and you can choose one by typing a number. +If possible, the setUp() method of the test suite should provide all necessary inputs for the respective tests. MITK provides several helper classes to generate synthetic test data, such as the mitk::ImageGenerator. If you have to load data from the hard disc for your test, you can use the method GetTestDataFilePath(string fileName). For an example of loading data from the MITK_DATA_DIR check the mitkIOUtilTestSuite. -\note This way you can not set additional input, such as images. +\section GeneralTestsPredefinedAssertions Predefined assertions -Alternatively you can give your test driver the name of your test as parameter. Then this test will be started directly. You are also allowed to give more parameters which are then given to the main test method as parameters (argv[]). +MITK and CppUnit offer predefined assertions, i.e. helper methods which will help to compare your data against a certain reference. All basic types are covered by CppUnit assertions, such as CPPUNIT_ASSERT. For examples, please check the CppUnit documentation. MITK further offers comparison tools for floating point numbers, vectors, images, surfaces and point sets. A complete list of assertion macros is given in \ref MITKTestingAPI. -If you want to use ctest instead of the test driver you need to start a command line, go to the binary directory of MITK and call ctest. To avoid errors, check if your path variable contains all relevant paths to start MITK. +An example to compare images: +\code + MITK_ASSERT_EQUAL(image, reference, "Checks if image is equal to a reference"); +\endcode -\section GeneralTestsSection4 MITK Testing Macros +By default, the method uses an mitk::eps for floating point comparison, but this can be adapted. It can be necessary to write your own assertion for your own data meeting your special requirements. Recommended examples are all equal test suites for basic data types (mitkImageEqualTest, mitkSurfaceEqualTest and mitkPointSetEqualTest). -MITK offers testing macros to simplify testing, e.g. to test your testing conditions. These macros can be found in the header mitkTestingMacros.h . +\section GeneralTestsExample An example +\include Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp +\section GeneralTestsFurtherInfo Further information +More examples can be found in the corresponding bugsquashing presentation. */ + +\section GeneralTestsDeprecatedOldTestingStyle Deprecated macros + +All tests with MITK_TEST_BEGIN(); and MITK_TEST_END(); use the deprecated old MITK testing style. If possible, they should be replaced with the new CppUnit style as explained before. Most of these test classes contain very unfortunate examples and should not be regarded as reference. diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/FirstSteps.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/FirstSteps.dox index 7b01d0b3e1..cb3f5cd61f 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/FirstSteps.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/FirstSteps.dox @@ -1,15 +1,16 @@ /** \page FirstSteps First steps in Development This section will show you how to extend MITK for your own project.
  • \subpage NewPluginPage
  • -
  • \subpage NewModulePage
  • +
  • \subpage NewModulePage
  • +
  • \subpage NewDataTypePage
  • \subpage NewViewPage
  • \subpage CMAKE_FAQ
  • \subpage StatemachineEditor
  • \subpage MiniAppCommandLineToolHowToPage
*/ diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewDataType.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewDataType.dox new file mode 100644 index 0000000000..e30e8f3e7d --- /dev/null +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewDataType.dox @@ -0,0 +1,52 @@ +/** + +\page NewDataTypePage How to create a new custom data type + +\tableofcontents + + +\section NewDataTypePagePrerequisites Prerequisites and further reading + +We will use some concepts during this tutorial which we assume you are aware of, as well as taking advantage of infrastructure which needs to be set up. The following is a list of prerequisites which should be present to effectively use this tutorial. + +
    +
  • An understanding of the general \ref DataManagementPage
  • +
  • An understanding about the \ref ModularizationPage "modularization of MITK"
  • +
  • We also assume you have created your own module "NewModule" ( \ref NewModulePage )
  • +
+ +Some concepts will only be briefly touched upon in this tutorial, for a more concise presentation of these concepts please refer to the following further reading. + +
    +
  • A general understanding of how the \ref ReaderWriterPage concept works
  • +
  • If you want to know more about the mitk rendering see \ref QVTKRendering
  • +
+ +\section NewDataTypePageCreatingANewDataType Creating a new data type + +A new data type needs to derive from mitk::BaseData in order to be handled by the mitk::DataStorage via mitk::DataNode. An example of a very simple data type is provided in the example module. This type encapsulates a string. + +\include mitkExampleDataStructure.h + +Overloading mitk::Equal to work with your data type will enable you to write simpler, standardized tests. + +\section NewDataTypePageAddingReadersAndWriters Adding readers and writers + +In order for your data type to be read from and written to disk, you need to implement readers and writers. In order for your readers/writers to be registered and available even if your module has not been loaded (usually after just starting the application), it is advisable to implement them separately in a autoload module. The default location for this is "YourModuleName/autoload/IO". + +More information regarding implementing IO and MimeTypes is available at \ref ReaderWriterPage. An example MimeType is implemented for the example data structure. + +\include mitkExampleIOMimeTypes.h + +\note{ You do not need to create your own class to manage your MimeTypes. Instead they can be defined within the Reader/Writer. } + +\section NewDataTypePageAddingReadersAndWriters Adding a mapper + +If your data type needs a special way to render its data for the user, you need to implement a new mapper. More information can be found at \ref QVTKRendering. + +

+If you meet any difficulties during this How-To, don't hesitate to ask on the MITK mailing list mitk-users@lists.sourceforge.net! +People there are kind and will try to help you. +If you notice that there is an error, or that the code has changed so the way shown here is no longer correct, please open a bug report a http://bugs.mitk.org .

+ +*/ diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewModule.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewModule.dox index 20c324fd0a..609cdd831d 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewModule.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/FirstSteps/NewModule.dox @@ -1,82 +1,122 @@ /** \page NewModulePage How to create a new MITK Module -\section NewModulePageCreateFolder 1) Create a Folder for your Module +\section NewModulePageCreateFolder Create a Folder for your Module First, create a folder for your module within /Modules e.g. 'NewModule'. You need to add the new Folder to the CMakeLists.txt in the Module directory as well as well. -Open /Modules/CMakeLists.txt, it should be pretty clear how to add the Module, just insert it into the set(module_dirs) section. +Open /Modules/CMakeLists.txt, insert it into the set(module_dirs) section. \code set(module_dirs ... NewModule ) \endcode -Inside the folder create a new folder called "Testing", which will later contain the module tests. -Also create subfolders for you sourceFiles, for example "NewModuleFilters" and "NewModuleSourceFiles". +A simple example module is provided in the MITK/Examples/FirstSteps/NewModule directory, it includes a new data type +(more information at \ref NewDataTypePage) and adds a MiniApp for that data type (more information at \ref MiniAppCommandLineToolHowToPage). -\section NewModulePageCreateCMakeLists 2) Create CMakeLists.txt - -Within your module create the following file named CMakeLists.txt with the following content: +Within the module we recommend using a Unix like directory structure. This helps others finding their way around your code. +Depending on your use case you might not need every directory. \code -MITK_CREATE_MODULE(NewModule #<-- module name - SUBPROJECTS - INCLUDE_DIRS NewModuleFilters NewModuleServices #<-- sub-folders of module - INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} - DEPENDS Mitk #<-- modules on which your module depends on -) - -ADD_SUBDIRECTORY(Testing) #<-- Directory for tests +NewModule/ + autoload/ + cmdapps/ + doc/ + include/ + resource/ + src/ + test/ \endcode -Choose a fitting module name. This name should only contain Letters (both upper- and lowercase), no numbers, no underscores etc. -This name will be used to qualify your Module within the MITK Framework, so make sure it is unique. -Typically, the name will be the same as name of the Folder the Module resides in. +Subsequently a quick description of what each directory contains. -It is good practice to create subfolders in your module to structure your classes. -Make sure to include these folders in the List of subfolders, or CMake will not find the internal Files. +\subsection NewModulePageCreateFolderAutoload autoload -In the DEPENDS section, you can enter the modules that your module requires to function. -You will not be able to use classes from modules that are not listed here. +This directory should not directly contain files. Instead it contains further directories each of which is its own module. -\section NewModulePageCreatefilesdotcmake 3) Create files.cmake +These modules provide functionality which should be available at application start, but will not be included by other modules. +Examples would be a module registering readers/writers or providing an interface for specific hardware. -Next, create a new file and name it files.cmake, containing the following: +For an example of an autoload module take a look at NewModule/autoload/IO. -\code -SET(CPP_FILES - NewModuleFilters/File1.cpp - NewModuleFilters/File2.cpp +\subsection NewModulePageCreateFolderCmdApps cmdapps - NewModuleServices/Filter1.cpp -) -\endcode +This directory contains all cmdapps (command line tools) related to your module. For more information see \ref MiniAppCommandLineToolHowToPage. -Add each .cpp file you create to this file. -Also, only add you .cpp files here, not the header files! +\subsection NewModulePageCreateFolderDoc doc -\section NewModulePageCreateTEstingEnvironment 4) Set up the Test environment +This directory contains the documentation for your module. -We also need to set up a testing environment where you can add your tests. -Inside your "Testing" Folder, create a new files.cmake containing the following: +\subsection NewModulePageCreateFolderInclude include -\code -SET(MODULE_TESTS - mitkNewModuleTest.cpp -) -\endcode +This directory contains all header files which might be included by other modules. -Also, create a new CMakeLists.text: +\subsection NewModulePageCreateFolderResource resource -\code -MITK_CREATE_MODULE_TESTS() -\endcode +This directory contains resources needed by your module, such as xmls, images or similar. + +\subsection NewModulePageCreateFolderSrc src + +This directory contains source and header files which should not be included by other modules. Further subdivision can help keeping it organized. +(e.g. src/DataManagement src/Algorithms) + +\subsection NewModulePageCreateFolderTest test + +This directory contains all tests for your module. + + +\section NewModulePageCreateCMakeLists Create CMakeLists.txt + +Within your module create a CMakeLists.txt using the MITK_CREATE_MODULE macro: + +An example: + +\include Examples/FirstSteps/NewModule/CMakeLists.txt + +If you do not choose a module name, one will be generated based on the folder name (In this case the resulting name will be MitkNewModule). +This name has to be unique across the entire project in order to avoid collisions. It should only contain Letters (both upper- and lowercase), +no numbers, no underscores etc. + +An example of an autoload module that sets its own name is: + +\include Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt + +the resulting name is MitkNewModuleIO. + +\note For more information about the parameters of the new module macro see mitkFunctionCreateModule.cmake + +\section NewModulePageCreatefilesdotcmake Create files.cmake + +Next, create a new file and name it files.cmake, containing the files of your module. + +An example: + +\include Examples/FirstSteps/NewModule/autoload/IO/files.cmake + +If you do not add a source file here it will not be compiled, unless it is included elsewhere. + +\section NewModulePageCreateTestingEnvironment Set up the Test environment + +Providing tests for your code is a very good way to save yourself a lot of debugging time and ensure +consistency. An example of a small test environment is provided in the NewModule example. + +Again you need a CMakeLists.txt, e.g.: + +\include Examples/FirstSteps/NewModule/test/CMakeLists.txt + +a files.cmake, e.g.: + +\include Examples/FirstSteps/NewModule/test/files.cmake + +and an actual test, e.g.: + +\include Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp -That's it! Enjoy your new module! After following these steps, it should look something like this: +For more information regarding tests please refer to \ref AboutTestingPage. -\imageMacro{NewModule.png,"Your shiny new module!",6} +That's it! Enjoy your new module! */ \ No newline at end of file diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox index c556bd47af..ee7517c3d1 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/GettingToKnow/Tutorial/Tutorial.dox @@ -1,46 +1,48 @@ /** \page TutorialPage The MITK Tutorial If you have set up and compiled MITK already and want to know more about developing with MITK you might want to read the \ref TutorialSection. If you want help setting up MITK and creating your own project using MITK you should take a look at \ref HowToNewProject. \section TutorialFirstSteps First steps in MITK If you are absolutely new to MITK you might want to read up on setting up MITK to use in your development. The following pages will help you in this task.
  • \subpage HowToNewProject "A comprehensive guide to setting up your own MITK project"
  • \ref BuildInstructionsPage "Building MITK"
  • \ref CMAKE_FAQ
\section TutorialSection Tutorial chapters This tutorial will give you an introduction to developing with MITK. We will start with configuring MITK to compile the tutorial, continue to show how to display and do basic interaction with images, and finally show how to build a plug-in and add new interactions. The source code of the examples can be found in Examples/Tutorial/ \n Two data files are used to execute the example code. \li Pic3D.nrrd \n This file contains an image and can be downloaded from http://mitk.org/download/tutorial-data/Pic3D.nrrd . \li lungs.vtk \n This file contains a surface and can be downloaded from http://mitk.org/download/tutorial-data/lungs.vtk . \li \subpage Step00Page "Step 0: Getting started" \li \subpage Step01Page "Step 1: Displaying an image" \li \subpage Step02Page "Step 2: Load one or more data sets" \li \subpage Step03Page "Step 3: Create 3D view" \li \subpage Step04Page "Step 4: Use several views to explore data" \li \subpage Step05Page "Step 5: Interactively add points" \li \subpage Step06Page "Step 6: Use an interactive region-grower" \li \subpage Step07Page "Step 7: Convert result of region growing into a surface" \li \subpage Step08Page "Step 8: Use QmitkStdMultiWidget as widget" \li \subpage Step09Page "Step 9: A plug-in" \li \subpage Step10Page "Step 10: How to use Interactor and how to implement new ones" +More advanced How-Tos can be found at \ref FirstSteps . + Enjoy MITK! */ diff --git a/Documentation/Doxygen/3-DeveloperManual/images/NewModule.png b/Documentation/Doxygen/3-DeveloperManual/images/NewModule.png deleted file mode 100644 index c379c6649a..0000000000 Binary files a/Documentation/Doxygen/3-DeveloperManual/images/NewModule.png and /dev/null differ diff --git a/Examples/CMakeLists.txt b/Examples/CMakeLists.txt index 960535e42b..5f55f7d253 100644 --- a/Examples/CMakeLists.txt +++ b/Examples/CMakeLists.txt @@ -1,63 +1,64 @@ set(MITK_DEFAULT_SUBPROJECTS MITK-Examples) #----------------------------------------------------------------------------- # Set-up example plugins #----------------------------------------------------------------------------- if(MITK_USE_BLUEBERRY) # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_example_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk OUTPUT_VARIABLE ${varname}) endmacro() set(MITK_EXAMPLE_PLUGIN_TARGETS ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) ctkFunctionExtractOptionNameAndValue(${mitk_example_plugin} plugin_name plugin_value) string(REPLACE "." "_" _plugin_target ${plugin_name}) list(APPEND MITK_EXAMPLE_PLUGIN_TARGETS ${_plugin_target}) mark_as_advanced(${${_plugin_target}_option_name}) endforeach() endif() #----------------------------------------------------------------------------- # Add example executables #----------------------------------------------------------------------------- set(MITK_DIR ${PROJECT_BINARY_DIR}) set(MITK_EXPORTS_FILE_INCLUDED 1) set(_example_dirs Dump MbiLog QtFreeRender Tutorial + FirstSteps # Overlays# depends on MitkQtWidgetsExt.. ) # some examples depend on Qt 5 if (MITK_USE_Qt5) list(APPEND _example_dirs QuickRender ) elseif (MITK_USE_Qt4) list(APPEND _example_dirs QtAppExample DumpDir ) endif() if(MITK_USE_BLUEBERRY) list(APPEND _example_dirs BlueBerryExampleLauncher ) endif() foreach(_example_dir ${_example_dirs}) add_subdirectory(${_example_dir}) endforeach() diff --git a/Examples/FirstSteps/CMakeLists.txt b/Examples/FirstSteps/CMakeLists.txt new file mode 100644 index 0000000000..1f6579406d --- /dev/null +++ b/Examples/FirstSteps/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(NewModule) \ No newline at end of file diff --git a/Examples/FirstSteps/NewModule/CMakeLists.txt b/Examples/FirstSteps/NewModule/CMakeLists.txt new file mode 100644 index 0000000000..ddad55247e --- /dev/null +++ b/Examples/FirstSteps/NewModule/CMakeLists.txt @@ -0,0 +1,12 @@ +MITK_CREATE_MODULE( + INCLUDE_DIRS + PUBLIC ${MITK_BINARY_DIR} + PRIVATE src/DataManagement + DEPENDS PUBLIC MitkCore + WARNINGS_AS_ERRORS + SUBPROJECTS MITK-Examples +) + +add_subdirectory(autoload/IO) +add_subdirectory(cmdapps) +add_subdirectory(test) diff --git a/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt b/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt new file mode 100644 index 0000000000..d5ca58f7ce --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt @@ -0,0 +1,10 @@ +MITK_CREATE_MODULE( NewModuleIO + INCLUDE_DIRS + PRIVATE src/IO + DEPENDS PUBLIC MitkNewModule MitkSceneSerialization + PACKAGE_DEPENDS + PRIVATE tinyxml + AUTOLOAD_WITH MitkCore + WARNINGS_AS_ERRORS + SUBPROJECTS MITK-Examples +) \ No newline at end of file diff --git a/Examples/FirstSteps/NewModule/autoload/IO/files.cmake b/Examples/FirstSteps/NewModule/autoload/IO/files.cmake new file mode 100644 index 0000000000..6fdfa62128 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/files.cmake @@ -0,0 +1,12 @@ +set(CPP_FILES + mitkExampleDataStructureReaderService.cpp + mitkExampleDataStructureReaderService.h + mitkExampleDataStructureSerializer.cpp + mitkExampleDataStructureSerializer.h + mitkExampleDataStructureWriterService.cpp + mitkExampleDataStructureWriterService.h + mitkExampleIOMimeTypes.cpp + mitkExampleIOMimeTypes.h + mitkNewModuleIOActivator.cpp +) + diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp new file mode 100644 index 0000000000..e910d119ca --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp @@ -0,0 +1,99 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 "mitkExampleDataStructureReaderService.h" + +// mitk includes +#include "mitkGeometry3D.h" +#include +#include "mitkExampleIOMimeTypes.h" + +// itk includes +#include "itksys/SystemTools.hxx" + +namespace mitk +{ + + ExampleDataStructureReaderService::ExampleDataStructureReaderService(const ExampleDataStructureReaderService& other) + : mitk::AbstractFileReader(other) + { + } + + ExampleDataStructureReaderService::ExampleDataStructureReaderService() + : mitk::AbstractFileReader( CustomMimeType( mitk::ExampleIOMimeTypes::EXAMPLE_MIMETYPE() ), "Default reader for the example data structure" ) + { + m_ServiceReg = this->RegisterService(); + } + + ExampleDataStructureReaderService::~ExampleDataStructureReaderService() + { + } + + std::vector > ExampleDataStructureReaderService::Read() + { + std::vector > result; + std::string location = GetInputLocation(); + + std::string ext = itksys::SystemTools::GetFilenameLastExtension(location); + ext = itksys::SystemTools::LowerCase(ext); + + if ( location == "") + { + MITK_ERROR << "No file name specified."; + } + try + { + std::ifstream file(location); + std::string content(""); + std::string line(""); + if (file.is_open()) + { + while (getline(file, line)) + { + content += line; + content += "\n"; + } + } + else + { + mitkThrow() << "Could not open file " << this->GetInputLocation() << " for reading."; + } + + mitk::ExampleDataStructure::Pointer outputData = mitk::ExampleDataStructure::New(); + outputData->SetData(content); + result.push_back(outputData.GetPointer()); + MITK_INFO << "Example file read"; + } + + catch (mitk::Exception e) + { + MITK_ERROR << e.GetDescription(); + } + catch(...) + { + MITK_ERROR << "Unknown error occurred while trying to read file."; + } + + return result; + } + + +} //namespace MITK + +mitk::ExampleDataStructureReaderService* mitk::ExampleDataStructureReaderService::Clone() const +{ + return new ExampleDataStructureReaderService(*this); +} diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h new file mode 100644 index 0000000000..563387da58 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h @@ -0,0 +1,53 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 __mitkExampleDataStructureReaderService_h +#define __mitkExampleDataStructureReaderService_h + +#include "mitkCommon.h" +#include +#include +#include +#include "mitkExampleDataStructure.h" + +namespace mitk +{ + + /** \brief The reader service for the MITK example data type + */ + + class ExampleDataStructureReaderService : public mitk::AbstractFileReader + { + public: + + typedef mitk::ExampleDataStructure OutputType; + + ExampleDataStructureReaderService(const ExampleDataStructureReaderService& other); + ExampleDataStructureReaderService(); + virtual ~ExampleDataStructureReaderService(); + + using AbstractFileReader::Read; + virtual std::vector > Read() override; + + private: + ExampleDataStructureReaderService* Clone() const override; + + us::ServiceRegistration m_ServiceReg; + }; + +} //namespace MITK + +#endif // __mitkExampleDataStructureReaderService_h diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp new file mode 100644 index 0000000000..3853425192 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp @@ -0,0 +1,71 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 "mitkExampleDataStructureSerializer.h" +#include "mitkExampleDataStructure.h" +#include "mitkIOUtil.h" + +#include + + +MITK_REGISTER_SERIALIZER(ExampleDataStructureSerializer) + + +mitk::ExampleDataStructureSerializer::ExampleDataStructureSerializer() +{ +} + + +mitk::ExampleDataStructureSerializer::~ExampleDataStructureSerializer() +{ +} + + +std::string mitk::ExampleDataStructureSerializer::Serialize() +{ + const ExampleDataStructure* exData = dynamic_cast( m_Data.GetPointer() ); + if (exData == NULL) + { + MITK_ERROR << " Object at " << (const void*) this->m_Data + << " is not an mitk::ExampleDataStructure. Cannot serialize as ExampleDataStructure."; + return ""; + } + + std::string filename( this->GetUniqueFilenameInWorkingDirectory() ); + filename += "_"; + filename += m_FilenameHint; + filename += ".txt"; + + std::string fullname(m_WorkingDirectory); + fullname += "/"; + fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str()); + + try + { + mitk::IOUtil::Save(exData, fullname); + } + catch (std::exception& e) + { + MITK_ERROR << " Error serializing object at " << (const void*) this->m_Data + << " to " + << fullname + << ": " + << e.what(); + return ""; + } + return filename; +} + diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.h new file mode 100644 index 0000000000..1e76b67071 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.h @@ -0,0 +1,39 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 mitkExampleDataStructureSerializer_h_included +#define mitkExampleDataStructureSerializer_h_included + +#include "mitkBaseDataSerializer.h" + +namespace mitk +{ +/** + \brief Serializes mitk::ExampleDataStructure for mitk::SceneIO +*/ +class ExampleDataStructureSerializer : public BaseDataSerializer +{ + public: + mitkClassMacro( ExampleDataStructureSerializer, BaseDataSerializer ); + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + virtual std::string Serialize() override; + protected: + ExampleDataStructureSerializer(); + virtual ~ExampleDataStructureSerializer(); +}; +} // namespace +#endif diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp new file mode 100644 index 0000000000..a42c23fd86 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp @@ -0,0 +1,95 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 "mitkExampleDataStructureWriterService.h" + +// itk includes +#include "itksys/SystemTools.hxx" + +// mitk includes +#include "mitkExampleIOMimeTypes.h" + +mitk::ExampleDataStructureWriterService::ExampleDataStructureWriterService() + : AbstractFileWriter(mitk::ExampleDataStructure::GetStaticNameOfClass(), CustomMimeType(mitk::ExampleIOMimeTypes::EXAMPLE_MIMETYPE()), "Default writer for the example data structure") +{ + RegisterService(); +} + +mitk::ExampleDataStructureWriterService::ExampleDataStructureWriterService(const mitk::ExampleDataStructureWriterService& other) + : AbstractFileWriter(other) +{ +} + + +mitk::ExampleDataStructureWriterService::~ExampleDataStructureWriterService() +{} + +mitk::ExampleDataStructureWriterService* mitk::ExampleDataStructureWriterService::Clone() const +{ + return new ExampleDataStructureWriterService(*this); +} + +void mitk::ExampleDataStructureWriterService::Write() +{ + MITK_INFO << "Writing ExampleDataStructure"; + InputType::ConstPointer input = dynamic_cast(this->GetInput()); + if (input.IsNull() ) + { + MITK_ERROR <<"Sorry, input to ExampleDataStructureWriterService is NULL!"; + return; + } + if ( this->GetOutputLocation().empty() ) + { + MITK_ERROR << "Sorry, filename has not been set!" ; + return ; + } + + std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetOutputLocation()); + ext = itksys::SystemTools::LowerCase(ext); + + // default extension is .txt + if(ext == "") + { + ext = ".txt"; + this->SetOutputLocation(this->GetOutputLocation() + ext); + } + + try + { + std::ofstream file(this->GetOutputLocation()); + + if ( file.is_open() ) + { + file << input->GetData(); + } + else + { + mitkThrow() << "Could not open file " << this->GetOutputLocation() << " for writing."; + } + + MITK_INFO << "Example Data Structure has been written"; + } + + catch (mitk::Exception e) + { + MITK_ERROR << e.GetDescription(); + } + catch (...) + { + MITK_ERROR << "Unknown error occurred while trying to write file."; + } + +} diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.h new file mode 100644 index 0000000000..1e571c2b21 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 __mitkExampleDataStructureWriterService_h +#define __mitkExampleDataStructureWriterService_h + +#include +#include + +namespace mitk +{ + + /** + * Writes example data strucutres to a file + * @ingroup Process + */ + class ExampleDataStructureWriterService : public mitk::AbstractFileWriter + { + public: + typedef mitk::ExampleDataStructure InputType; + + ExampleDataStructureWriterService(); + virtual ~ExampleDataStructureWriterService(); + + using AbstractFileWriter::Write; + virtual void Write() override; + + protected: + + ExampleDataStructureWriterService(const ExampleDataStructureWriterService& other); + virtual mitk::ExampleDataStructureWriterService* Clone() const override; + + }; + + +} // end of namespace mitk + +#endif //__mitkExampleDataStructureWriterService_h diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.cpp new file mode 100644 index 0000000000..7ac4701984 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.cpp @@ -0,0 +1,116 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 "mitkExampleIOMimeTypes.h" +#include "mitkIOMimeTypes.h" +#include +#include + +namespace mitk +{ + +std::vector ExampleIOMimeTypes::Get() +{ + std::vector mimeTypes; + + // order matters here (descending rank for mime types) + + mimeTypes.push_back(EXAMPLE_MIMETYPE().Clone()); + mimeTypes.push_back(EXAMPLE_TWO_MIMETYPE().Clone()); + + return mimeTypes; +} + +// Mime Types + +ExampleIOMimeTypes::ExampleDataStructureMimeType::ExampleDataStructureMimeType() + : CustomMimeType(EXAMPLE_MIMETYPE_NAME()) +{ + std::string category = "Example and Tutorial Data"; + this->SetCategory(category); + this->SetComment("Example data structure containing just a string"); + + this->AddExtension("example"); + this->AddExtension("txt"); +} + +bool ExampleIOMimeTypes::ExampleDataStructureMimeType::AppliesTo(const std::string &path) const +{ + bool canRead( CustomMimeType::AppliesTo(path) ); + + // fix for bug 18572 + // Currently this function is called for writing as well as reading, in that case + // the image information can of course not be read + // This is a bug, this function should only be called for reading. + if( ! itksys::SystemTools::FileExists( path.c_str() ) ) + { + return canRead; + } + //end fix for bug 18572 + + std::string ext = this->GetExtension( path ); + ext = itksys::SystemTools::LowerCase( ext ); + + if( ext == ".txt" ) + { + // we could test something here + if( false ) + { + MITK_WARN << "Can not read .txt file as ExampleDataStructure"; + canRead = false; + } + } + + return canRead; +} + +ExampleIOMimeTypes::ExampleDataStructureMimeType* ExampleIOMimeTypes::ExampleDataStructureMimeType::Clone() const +{ + return new ExampleDataStructureMimeType(*this); +} + + +ExampleIOMimeTypes::ExampleDataStructureMimeType ExampleIOMimeTypes::EXAMPLE_MIMETYPE() +{ + return ExampleDataStructureMimeType(); +} + +CustomMimeType ExampleIOMimeTypes::EXAMPLE_TWO_MIMETYPE() +{ + CustomMimeType mimeType(EXAMPLE_TWO_MIMETYPE_NAME()); + std::string category = "Example and Tutorial Data"; + mimeType.SetComment("Simpler Example Data MimeType"); + mimeType.SetCategory(category); + mimeType.AddExtension("example2"); + return mimeType; +} + +// Names +std::string ExampleIOMimeTypes::EXAMPLE_MIMETYPE_NAME() +{ + // create a unique and sensible name for this mime type + static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".examples.example-data-structure"; + return name; +} + +std::string ExampleIOMimeTypes::EXAMPLE_TWO_MIMETYPE_NAME() +{ + // create a unique and sensible name for this mime type + static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".examples.example-data-structure-the-second"; + return name; +} + +} diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.h new file mode 100644 index 0000000000..f24c89bd33 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleIOMimeTypes.h @@ -0,0 +1,58 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 MITKEXAMPLEIOMIMETYPES_H +#define MITKEXAMPLEIOMIMETYPES_H + +#include "mitkCustomMimeType.h" + +#include + +namespace mitk { + +class ExampleIOMimeTypes +{ +public: + + // Deriving your own MimeType will probably be overkill in most situations. + class ExampleDataStructureMimeType : public CustomMimeType + { + public: + ExampleDataStructureMimeType(); + virtual bool AppliesTo(const std::string &path) const override; + virtual ExampleDataStructureMimeType* Clone() const override; + }; + + static ExampleDataStructureMimeType EXAMPLE_MIMETYPE(); + static std::string EXAMPLE_MIMETYPE_NAME(); + + // Simpler method of creating a new MimeType + static CustomMimeType EXAMPLE_TWO_MIMETYPE(); + static std::string EXAMPLE_TWO_MIMETYPE_NAME(); + + // Get all example Mime Types + static std::vector Get(); + +private: + + // purposely not implemented + ExampleIOMimeTypes(); + ExampleIOMimeTypes(const ExampleIOMimeTypes&); +}; + +} + +#endif // MITKEXAMPLEIOMIMETYPES_H diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkNewModuleIOActivator.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkNewModuleIOActivator.cpp new file mode 100644 index 0000000000..f8093aeaa2 --- /dev/null +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkNewModuleIOActivator.cpp @@ -0,0 +1,77 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 +#include + +#include + +#include + +#include "mitkExampleIOMimeTypes.h" + +namespace mitk +{ + /** + \brief Registers services for example module. + */ + class NewModuleIOActivator : public us::ModuleActivator + { + public: + + void Load(us::ModuleContext* context) override + { + // We can register our read/write services with a custom service ranking + // services with a higher ranking are prioritized, default us 0 + us::ServiceProperties props; + props[ us::ServiceConstants::SERVICE_RANKING() ] = 10; + + m_MimeTypes = mitk::ExampleIOMimeTypes::Get(); + for (std::vector::const_iterator mimeTypeIter = m_MimeTypes.begin(), + iterEnd = m_MimeTypes.end(); mimeTypeIter != iterEnd; ++mimeTypeIter) + { + context->RegisterService(*mimeTypeIter, props); + } + + m_ExampleDataStructureReaderService = new ExampleDataStructureReaderService(); + + m_ExampleDataStructureWriterService = new ExampleDataStructureWriterService(); + } + + void Unload(us::ModuleContext*) override + { + for (unsigned int loop(0); loop < m_MimeTypes.size(); ++loop) + { + delete m_MimeTypes.at(loop); + } + + delete m_ExampleDataStructureReaderService; + + delete m_ExampleDataStructureWriterService; + + } + + private: + + ExampleDataStructureReaderService * m_ExampleDataStructureReaderService; + + ExampleDataStructureWriterService * m_ExampleDataStructureWriterService; + + std::vector m_MimeTypes; + + }; +} + +US_EXPORT_MODULE_ACTIVATOR(mitk::NewModuleIOActivator) diff --git a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt b/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt old mode 100755 new mode 100644 similarity index 56% copy from Modules/DiffusionImaging/MiniApps/CMakeLists.txt copy to Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt index 84dd09cf5b..b6219118e7 --- a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt +++ b/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt @@ -1,128 +1,76 @@ -option(BUILD_DiffusionMiniApps "Build commandline tools for diffusion" OFF) +option(BUILD_NewModuleMiniApps "Build commandline tools for the example module" OFF) -if(BUILD_DiffusionMiniApps OR MITK_BUILD_ALL_APPS) - - - find_package(OpenMP) - if(NOT OPENMP_FOUND) - message("OpenMP is not available.") - endif() - if(OPENMP_FOUND) - message(STATUS "Found OpenMP.") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - endif() +if(BUILD_NewModuleMiniApps) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) - - # list of diffusion miniapps + # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" - set( diffusionminiapps - DwiDenoising^^ - ImageResampler^^ - NetworkCreation^^MitkFiberTracking_MitkConnectomics - NetworkStatistics^^MitkConnectomics - ExportShImage^^ - Fiberfox^^MitkFiberTracking - MultishellMethods^^MitkFiberTracking - PeaksAngularError^^MitkFiberTracking - PeakExtraction^^MitkFiberTracking - FiberExtraction^^MitkFiberTracking - FiberProcessing^^MitkFiberTracking - FiberDirectionExtraction^^MitkFiberTracking - LocalDirectionalFiberPlausibility^^MitkFiberTracking - StreamlineTracking^^MitkFiberTracking - GibbsTracking^^MitkFiberTracking - CopyGeometry^^ - DiffusionIndices^^ - TractometerMetrics^^MitkFiberTracking - QballReconstruction^^ - Registration^^ - FileFormatConverter^^MitkFiberTracking - TensorReconstruction^^ - TensorDerivedMapsExtraction^^ - DICOMLoader^^ - DFTraining^^MitkFiberTracking - DFTracking^^MitkFiberTracking + set( miniapps + ExampleToUpperCaseMiniApp^^ ) - foreach(diffusionminiapp ${diffusionminiapps}) + foreach(miniapp ${miniapps}) # extract mini app name and dependencies - string(REPLACE "^^" "\\;" miniapp_info ${diffusionminiapp}) + string(REPLACE "^^" "\\;" miniapp_info ${miniapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} - DEPENDS MitkCore MitkDiffusionCore ${dependencies_list} + DEPENDS MitkNewModule MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK - CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp + CPP_FILES ${appname}.cpp ) if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() - # This mini app does not depend on mitkDiffusionImaging at all - mitk_create_executable(Dicom2Nrrd - DEPENDS MitkCore - CPP_FILES Dicom2Nrrd.cpp mitkCommandLineParser.cpp - ) - - # On Linux, create a shell script to start a relocatable application - if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) - endif() - - if(EXECUTABLE_IS_ENABLED) - MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) - endif() - endif() diff --git a/Examples/FirstSteps/NewModule/cmdapps/ExampleToUpperCaseMiniApp.cpp b/Examples/FirstSteps/NewModule/cmdapps/ExampleToUpperCaseMiniApp.cpp new file mode 100644 index 0000000000..09fd150ecf --- /dev/null +++ b/Examples/FirstSteps/NewModule/cmdapps/ExampleToUpperCaseMiniApp.cpp @@ -0,0 +1,108 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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. + +===================================================================*/ + +// std includes +#include +#include + +// CTK includes +#include "mitkCommandLineParser.h" + +// MITK includes +#include "mitkExampleDataStructure.h" +#include + +int main( int argc, char* argv[] ) +{ + mitkCommandLineParser parser; + + parser.setTitle( "To Upper Case" ); + parser.setCategory( "MITK-Examples" ); + parser.setDescription( "" ); + parser.setContributor( "MBI" ); + + parser.setArgumentPrefix( "--", "-" ); + parser.addArgument( + "input", "i", mitkCommandLineParser::InputFile, "Input file", "input file (.txt/.example)", us::Any(), false ); + parser.addArgument( "output", + "o", + mitkCommandLineParser::OutputFile, + "Output file", + "where to save the output (.txt/.example)", + us::Any(), + false ); + + parser.addArgument( + "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose output" ); + + map parsedArgs = parser.parseArguments( argc, argv ); + if ( parsedArgs.size() == 0 ) + return EXIT_FAILURE; + + // default values + bool verbose( false ); + + // parse command line arguments + std::string inFilename = us::any_cast( parsedArgs[ "input" ] ); + std::string outFileName = us::any_cast( parsedArgs[ "output" ] ); + + // if optional flag is present + if ( parsedArgs.count( "verbose" ) ) + verbose = us::any_cast( parsedArgs[ "verbose" ] ); + + try + { + // load file + std::vector inVector = mitk::IOUtil::Load( inFilename ); + if ( inVector.empty() ) + { + std::string errorMessage = "File at " + inFilename + " could not be read. Aborting."; + MITK_ERROR << errorMessage; + return EXIT_FAILURE; + } + mitk::BaseData* inBaseData = inVector.at( 0 ); + mitk::ExampleDataStructure* inExample = dynamic_cast( inBaseData ); + + // do creation + mitk::ExampleDataStructure::Pointer outExample = mitk::ExampleDataStructure::New(); + std::string data = inExample->GetData(); + std::transform( data.begin(), data.end(), data.begin(), ::toupper ); + outExample->SetData( data ); + + std::cout << "searching writer"; + + mitk::IOUtil::SaveBaseData( outExample.GetPointer(), outFileName ); + + return EXIT_SUCCESS; + } + catch ( itk::ExceptionObject e ) + { + std::cout << e; + return EXIT_FAILURE; + } + catch ( std::exception e ) + { + std::cout << e.what(); + return EXIT_FAILURE; + } + catch ( ... ) + { + std::cout << "ERROR!?!"; + return EXIT_FAILURE; + } + std::cout << "DONE"; + return EXIT_SUCCESS; +} diff --git a/Examples/FirstSteps/NewModule/doc/Readme.txt b/Examples/FirstSteps/NewModule/doc/Readme.txt new file mode 100644 index 0000000000..0a9980df7e --- /dev/null +++ b/Examples/FirstSteps/NewModule/doc/Readme.txt @@ -0,0 +1 @@ +This directory should contain documentation for your module. \ No newline at end of file diff --git a/Examples/FirstSteps/NewModule/files.cmake b/Examples/FirstSteps/NewModule/files.cmake new file mode 100644 index 0000000000..7bf639d033 --- /dev/null +++ b/Examples/FirstSteps/NewModule/files.cmake @@ -0,0 +1,6 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + +set(CPP_FILES + # DataStructures + DataManagement/mitkExampleDataStructure.cpp +) diff --git a/Examples/FirstSteps/NewModule/include/mitkExampleDataStructure.h b/Examples/FirstSteps/NewModule/include/mitkExampleDataStructure.h new file mode 100644 index 0000000000..aee319fe34 --- /dev/null +++ b/Examples/FirstSteps/NewModule/include/mitkExampleDataStructure.h @@ -0,0 +1,87 @@ + +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 _MITK_ExampleDataStructure_H +#define _MITK_ExampleDataStructure_H + +#include + +#include "mitkBaseData.h" + +namespace mitk +{ +/** +* \brief Example Data Structure +* +* This class is an example of deriving your own data structure based on mitk::BaseData . +*/ +class MITKNEWMODULE_EXPORT ExampleDataStructure : public BaseData +{ +public: + // virtual methods that need to be implemented + virtual void UpdateOutputInformation() override; + virtual void SetRequestedRegionToLargestPossibleRegion() override; + virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override; + virtual bool VerifyRequestedRegion() override; + virtual void SetRequestedRegion( const itk::DataObject* ) override; + + // Macros + mitkClassMacro( ExampleDataStructure, BaseData ); + itkFactorylessNewMacro( Self ) itkCloneMacro( Self ) + + ////////////////// Interface /////////////////// + + // Get macros + itkGetMacro( Data, std::string ); + itkGetConstMacro( Data, std::string ); + + // Set macros + itkSetMacro( Data, std::string ); + + /** + * \brief Append a string to the data string + * + * Takes a string that is appended to the data string. + * + * \param input string to be appended + */ + void AppendAString( const std::string input ); + +protected: + ExampleDataStructure(); + virtual ~ExampleDataStructure(); + + // this string is the data stored in this example data structure + std::string m_Data; + +private: +}; + +/** +* \brief Returns true if the example data structures are considered equal. +* +* They are considered equal if their string is equal +*/ + +MITKNEWMODULE_EXPORT bool Equal( mitk::ExampleDataStructure* leftHandSide, + mitk::ExampleDataStructure* rightHandSide, + mitk::ScalarType eps, + bool verbose ); + +} // namespace mitk + +#endif /* _MITK_ExampleDataStructure_H */ diff --git a/Examples/FirstSteps/NewModule/resource/Readme.txt b/Examples/FirstSteps/NewModule/resource/Readme.txt new file mode 100644 index 0000000000..2643a3523e --- /dev/null +++ b/Examples/FirstSteps/NewModule/resource/Readme.txt @@ -0,0 +1 @@ +This directory should contain resources, such as images, presets, xmls or similar. \ No newline at end of file diff --git a/Examples/FirstSteps/NewModule/src/DataManagement/mitkExampleDataStructure.cpp b/Examples/FirstSteps/NewModule/src/DataManagement/mitkExampleDataStructure.cpp new file mode 100644 index 0000000000..6f53ec6456 --- /dev/null +++ b/Examples/FirstSteps/NewModule/src/DataManagement/mitkExampleDataStructure.cpp @@ -0,0 +1,98 @@ + +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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 "mitkExampleDataStructure.h" +#include "mitkGeometry3D.h" + +// implementation of virtual methods + +void mitk::ExampleDataStructure::UpdateOutputInformation() +{ + +} + +void mitk::ExampleDataStructure::SetRequestedRegionToLargestPossibleRegion() +{ + +} + +bool mitk::ExampleDataStructure::RequestedRegionIsOutsideOfTheBufferedRegion() +{ + return false; +} + +bool mitk::ExampleDataStructure::VerifyRequestedRegion() +{ + return true; +} + +void mitk::ExampleDataStructure::SetRequestedRegion(const itk::DataObject *) +{ + +} + +/* Constructor and Destructor */ +mitk::ExampleDataStructure::ExampleDataStructure() +: m_Data("Initialized") +{ + this->SetGeometry(mitk::Geometry3D::New()); +} + +mitk::ExampleDataStructure::~ExampleDataStructure() +{ +} + +void mitk::ExampleDataStructure::AppendAString(const std::string input) +{ + m_Data.append( input ); +} + + +bool mitk::Equal( mitk::ExampleDataStructure* leftHandSide, mitk::ExampleDataStructure* rightHandSide, mitk::ScalarType /*eps*/, bool verbose ) +{ + bool noDifferenceFound = true; + + if( rightHandSide == NULL ) + { + if(verbose) + { + MITK_INFO << "[Equal( ExampleDataStructure*, ExampleDataStructure* )] rightHandSide NULL."; + } + return false; + } + + if( leftHandSide == NULL ) + { + if(verbose) + { + MITK_INFO << "[Equal( ExampleDataStructure*, ExampleDataStructure* )] leftHandSide NULL."; + } + return false; + } + + if (!(leftHandSide->GetData() == rightHandSide->GetData()) ) + { + if(verbose) + { + MITK_INFO << "[Equal( ExampleDataStructure*, ExampleDataStructure* )] Data not equal. "; + MITK_INFO << leftHandSide->GetData() << " != " << rightHandSide->GetData(); + } + noDifferenceFound = false; + } + + return noDifferenceFound; +} diff --git a/Examples/FirstSteps/NewModule/test/CMakeLists.txt b/Examples/FirstSteps/NewModule/test/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Examples/FirstSteps/NewModule/test/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Examples/FirstSteps/NewModule/test/files.cmake b/Examples/FirstSteps/NewModule/test/files.cmake new file mode 100644 index 0000000000..f365da9ce1 --- /dev/null +++ b/Examples/FirstSteps/NewModule/test/files.cmake @@ -0,0 +1,7 @@ +set(MODULE_TESTS + mitkExampleDataStructureReaderWriterTest.cpp + mitkExampleDataStructureTest.cpp +) + +SET(MODULE_CUSTOM_TESTS +) diff --git a/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureReaderWriterTest.cpp b/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureReaderWriterTest.cpp new file mode 100644 index 0000000000..0a44cc952f --- /dev/null +++ b/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureReaderWriterTest.cpp @@ -0,0 +1,74 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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. + +===================================================================*/ + +// Testing +#include "mitkTestingMacros.h" +#include "mitkTestFixture.h" + +// std includes +#include + +// MITK includes +#include "mitkExampleDataStructure.h" +#include "mitkIOUtil.h" + +// VTK includes +#include + +class mitkExampleDataStructureReaderWriterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkExampleDataStructureReaderWriterTestSuite); + + // Test saving/loading + MITK_TEST(ReadWrite_ExampleData_SavedAndLoadedDataEqualToExample); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::ExampleDataStructure::Pointer m_Data; + std::string m_DefaultDataString; + +public: + + /** + * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used members for a new test case. (If the members are not used in a test, the method does not need to be called). + */ + void setUp() override + { + m_DefaultDataString = "This is the example data content\nAnd a second line\n"; + m_Data = mitk::ExampleDataStructure::New(); + m_Data->SetData(m_DefaultDataString); + } + + void tearDown() override + { + m_DefaultDataString = ""; + m_Data = nullptr; + } + + void ReadWrite_ExampleData_SavedAndLoadedDataEqualToExample() + { + std::string path = mitk::IOUtil::GetTempPath() + "ExampleDataOutput.txt"; + mitk::IOUtil::SaveBaseData(m_Data, path); + mitk::ExampleDataStructure::Pointer loadedData = dynamic_cast(mitk::IOUtil::LoadBaseData(path).GetPointer()); + + itksys::SystemTools::RemoveFile(path); + + CPPUNIT_ASSERT_MESSAGE("Comparing created and loaded example data.", mitk::Equal(m_Data, loadedData, mitk::eps, true)); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkExampleDataStructureReaderWriter) diff --git a/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp b/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp new file mode 100644 index 0000000000..e94b0ce60b --- /dev/null +++ b/Examples/FirstSteps/NewModule/test/mitkExampleDataStructureTest.cpp @@ -0,0 +1,71 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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. + +===================================================================*/ + +// Testing +#include "mitkTestingMacros.h" +#include "mitkTestFixture.h" + +// std includes +#include + +// MITK includes +#include "mitkExampleDataStructure.h" + +// VTK includes +#include + +class mitkExampleDataStructureTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkExampleDataStructureTestSuite); + + // Test the append method + MITK_TEST(Append_ExampleString_AddsExampleStringToData); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::ExampleDataStructure::Pointer m_Data; + std::string m_DefaultDataString; + +public: + + /** + * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used members for a new test case. (If the members are not used in a test, the method does not need to be called). + */ + void setUp() override + { + m_DefaultDataString = "This is the example data content\nAnd a second line\n"; + m_Data = mitk::ExampleDataStructure::New(); + m_Data->SetData(m_DefaultDataString); + } + + void tearDown() override + { + m_DefaultDataString = ""; + m_Data = nullptr; + } + + void Append_ExampleString_AddsExampleStringToData() + { + std::string appendedString = "And a third line\n"; + std::string wholeString = m_DefaultDataString + appendedString; + m_Data->AppendAString(appendedString); + + CPPUNIT_ASSERT_MESSAGE("Checking whether string was correctly appended.", m_Data->GetData() == wholeString); + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkExampleDataStructure) diff --git a/Modules/CommandLine/CMakeLists.txt b/Modules/CommandLine/CMakeLists.txt new file mode 100644 index 0000000000..d0ab40a745 --- /dev/null +++ b/Modules/CommandLine/CMakeLists.txt @@ -0,0 +1,7 @@ +MITK_CREATE_MODULE( + INCLUDE_DIRS + PUBLIC include/ + PRIVATE src/ + WARNINGS_AS_ERRORS + SUBPROJECTS MITK-Modules +) diff --git a/Modules/CommandLine/files.cmake b/Modules/CommandLine/files.cmake new file mode 100644 index 0000000000..18618b684a --- /dev/null +++ b/Modules/CommandLine/files.cmake @@ -0,0 +1,5 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + +set(CPP_FILES + mitkCommandLineParser.cpp +) diff --git a/Modules/CommandLine/include/mitkCommandLineParser.h b/Modules/CommandLine/include/mitkCommandLineParser.h new file mode 100644 index 0000000000..1419979e4a --- /dev/null +++ b/Modules/CommandLine/include/mitkCommandLineParser.h @@ -0,0 +1,382 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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. + +===================================================================*/ +/*========================================================================= + + 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 __mitkCommandLineParser_h +#define __mitkCommandLineParser_h + +#include +#include + +#include + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4251 ) +#endif + +/** + * + * The MITK command line parser, based on the CTK command line parser. + * + * Use this class to add information about the command line arguments + * your program understands and to easily parse them from a given list + * of strings. + * + * This parser provides the following features: + * + *
    + *
  • Add arguments by supplying a long name and/or a short name. + * Arguments are validated using a regular expression. They can have + * a default value and a help string.
  • + *
  • Deprecated arguments.
  • + *
  • Custom regular expressions for argument validation.
  • + *
  • Set different argument name prefixes for native platform look and feel.
  • + *
  • Create a help text for the command line arguments with support for + * grouping arguments.
  • + *
+ * + * The main difference between the MITK command line parser and the CTK command line + * parser is that the former does not depend on Qt. Apart from that an image type was + * added and XML output improved for automatic GUI generation. + * + * std::out is used for output to keep dependencies to a minimum. + */ + +using namespace std; + +class MITKCOMMANDLINE_EXPORT mitkCommandLineParser +{ +public: + enum Type + { + String = 0, + Bool = 1, + StringList = 2, + Int = 3, + Float = 4, + InputDirectory = 5, + InputFile = 6, + OutputDirectory = 7, + OutputFile = 8, + InputImage = 9 + }; + + typedef std::vector StringContainerType; + + mitkCommandLineParser(); + + ~mitkCommandLineParser(); + + /** + * Parse a given list of command line arguments. + * + * This method parses a list of string elements considering the known arguments + * added by calls to addArgument(). If any one of the argument + * values does not match the corresponding regular expression, + * ok is set to false and an empty map object is returned. + * + * The keys in the returned map object correspond to the long argument string, + * if it is not empty. Otherwise, the short argument string is used as key. The + * us::Any values can safely be converted to the type specified in the + * addArgument() method call. + * + * @param arguments A StringContainerType containing command line arguments. + * @param ok A pointer to a boolean variable. Will be set to true + * if all regular expressions matched, false otherwise. + * @return A map object mapping the long argument (if empty, the short one) + * to a us::Any containing the value. + */ + + map parseArguments( const StringContainerType& arguments, bool* ok = nullptr ); + + /** + * Convenient method allowing to parse a given list of command line arguments. + * @see parseArguments(const StringContainerType &, bool*) + */ + map parseArguments( int argc, char** argv, bool* ok = nullptr ); + + /** + * Returns a detailed error description if a call to parseArguments() + * failed. + * + * @return The error description, empty if no error occured. + * @see parseArguments(const StringContainerType&, bool*) + */ + string errorString() const; + + /** + * This method returns all unparsed arguments, i.e. all arguments + * for which no long or short name has been registered via a call + * to addArgument(). + * + * @see addArgument() + * + * @return A list containing unparsed arguments. + */ + const StringContainerType& unparsedArguments() const; + + /** + * Checks if the given argument has been added via a call + * to addArgument(). + * + * @see addArgument() + * + * @param argument The argument to be checked. + * @return true if the argument was added, false + * otherwise. + */ + bool argumentAdded( const string& argument ) const; + + /** + * Checks if the given argument has been parsed successfully by a previous + * call to parseArguments(). + * + * @param argument The argument to be checked. + * @return true if the argument was parsed, false + * otherwise. + */ + bool argumentParsed( const string& argument ) const; + + /** + * Adds a command line argument. An argument can have a long name + * (like --long-argument-name), a short name (like -l), or both. The type + * of the argument can be specified by using the type parameter. + * The following types are supported: + * + * + * + * + * + * + * + * + *
Type# of parametersDefault regular exprExample
us::Any::String1.*--test-string StringParameter
us::Any::Bool0does not apply--enable-something
us::Any::StringList-1.*--test-list string1 string2
us::Any::Int1-?[0-9]+--test-int -5
+ * + * The regular expressions are used to validate the parameters of command line + * arguments. You can restrict the valid set of parameters by calling + * setExactMatchRegularExpression() for your argument. + * + * Optionally, a help string and a default value can be provided for the argument. If + * the us::Any type of the default value does not match type, an + * exception is thrown. Arguments with default values are always returned by + * parseArguments(). + * + * You can also declare an argument deprecated, by setting deprecated + * to true. Alternatively you can add a deprecated argument by calling + * addDeprecatedArgument(). + * + * If the long or short argument has already been added, or if both are empty strings, + * the method call has no effect. + * + * @param longarg The long argument name. + * @param shortarg The short argument name. + * @param type The argument type (see the list above for supported types). + * @param argLabel The label of this argument, when auto generated interface is used. + * @param argHelp A help string describing the argument. + * @param defaultValue A default value for the argument. + * @param ignoreRest All arguments after the current one will be ignored. + * @param deprecated Declares the argument deprecated. + * + * @see setExactMatchRegularExpression() + * @see addDeprecatedArgument() + * @throws std::logic_error If the us::Any type of defaultValue + * does not match type, a std::logic_error is thrown. + */ + void addArgument( const string& longarg, + const string& shortarg, + Type type, + const string& argLabel, + const string& argHelp = string(), + const us::Any& defaultValue = us::Any(), + bool optional = true, + bool ignoreRest = false, + bool deprecated = false ); + + /** + * Adds a deprecated command line argument. If a deprecated argument is provided + * on the command line, argHelp is displayed in the console and + * processing continues with the next argument. + * + * Deprecated arguments are grouped separately at the end of the help text + * returned by helpText(). + * + * @param longarg The long argument name. + * @param shortarg The short argument name. + * @param argHelp A help string describing alternatives to the deprecated argument. + */ + void + addDeprecatedArgument( const string& longarg, const string& shortarg, const string& argLabel, const string& argHelp ); + + /** + * Sets a custom regular expression for validating argument parameters. The method + * errorString() can be used the get the last error description. + * + * @param argument The previously added long or short argument name. + * @param expression A regular expression which the arugment parameters must match. + * @param exactMatchFailedMessage An error message explaining why the parameter did + * not match. + * + * @return true if the argument was found and the regular expression was set, + * false otherwise. + * + * @see errorString() + */ + bool setExactMatchRegularExpression( const string& argument, + const string& expression, + const string& exactMatchFailedMessage ); + + /** + * The field width for the argument names without the help text. + * + * @return The argument names field width in the help text. + */ + std::string::size_type fieldWidth() const; + + /** + * Creates a help text containing properly formatted argument names and help strings + * provided by calls to addArgument(). The arguments can be grouped by + * using beginGroup() and endGroup(). + * + * @param charPad The padding character. + * @return The formatted help text. + */ + string helpText() const; + + /** + * Sets the argument prefix for long and short argument names. This can be used + * to create native command line arguments without changing the calls to + * addArgument(). For example on Unix-based systems, long argument + * names start with "--" and short names with "-", while on Windows argument names + * always start with "/". + * + * Note that all methods in mitkCommandLineParser which take an argument name + * expect the name as it was supplied to addArgument. + * + * Example usage: + * + * \code + * ctkCommandLineParser parser; + * parser.setArgumentPrefix("--", "-"); + * parser.addArgument("long-argument", "l", us::Any::String); + * StringContainerType args; + * args << "program name" << "--long-argument Hi"; + * parser.parseArguments(args); + * \endcode + * + * @param longPrefix The prefix for long argument names. + * @param shortPrefix The prefix for short argument names. + */ + void setArgumentPrefix( const string& longPrefix, const string& shortPrefix ); + + /** + * Begins a new group for documenting arguments. All newly added arguments via + * addArgument() will be put in the new group. You can close the + * current group by calling endGroup() or be opening a new group. + * + * Note that groups cannot be nested and all arguments which do not belong to + * a group will be listed at the top of the text created by helpText(). + * + * @param description The description of the group + */ + void beginGroup( const string& description ); + + /** + * Ends the current group. + * + * @see beginGroup(const string&) + */ + void endGroup(); + + /** + * Can be used to teach the parser to stop parsing the arguments and return False when + * an unknown argument is encountered. By default StrictMode is disabled. + * + * @see parseArguments(const StringContainerType &, bool*) + */ + void setStrictModeEnabled( bool strictMode ); + + /** + * Is used to generate an XML output for any commandline program. + */ + void generateXmlOutput(); + + /** + * Is used to set the title of the auto generated interface. + * + * @param title The title of the app. + */ + void setTitle( std::string title ); + /** + * Is used to set the contributor for the help view in the auto generated interface. + * + * @param contributor Contributor of the app. + */ + void setContributor( std::string contributor ); + /** + * Is used to categorize the apps in the commandline module. + * + * @param category The category of the app. + */ + void setCategory( std::string category ); + /** + * Is used as the help text in the auto generated interface. + * + * @param description A short description for the app. + */ + void setDescription( std::string description ); + /** + * Is used to group several Parameters in one groupbox in the auto generated interface. + * Default name is "Parameters", with the tooltip: "Groupbox containing parameters." + * + * To change the group of several arguments, call this method before the arguments are added. + * + * @param name The name of the groupbox. + * @param tooltip The tooltip of the groupbox. + */ + void changeParameterGroup( std::string name, std::string tooltip ); + +private: + class ctkInternal; + ctkInternal* Internal; + + string Title; + string Contributor; + string Category; + string Description; + string ParameterGroupName; + string ParameterGroupDescription; +}; + +#endif diff --git a/Modules/CommandLine/src/mitkCommandLineParser.cpp b/Modules/CommandLine/src/mitkCommandLineParser.cpp new file mode 100644 index 0000000000..a8447550bc --- /dev/null +++ b/Modules/CommandLine/src/mitkCommandLineParser.cpp @@ -0,0 +1,960 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +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. + +===================================================================*/ +/*========================================================================= + + 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. + +=========================================================================*/ + +// STL includes +#include +#include + +// MITK includes +#include "mitkCommandLineParser.h" + +using namespace std; + +namespace +{ +// -------------------------------------------------------------------------- +class CommandLineParserArgumentDescription +{ +public: + CommandLineParserArgumentDescription( const string& longArg, + const string& longArgPrefix, + const string& shortArg, + const string& shortArgPrefix, + mitkCommandLineParser::Type type, + const string& argHelp, + const string& argLabel, + const us::Any& defaultValue, + bool ignoreRest, + bool deprecated, + bool optional, + string& argGroup, + string& groupDescription ) + : LongArg( longArg ) + , LongArgPrefix( longArgPrefix ) + , ShortArg( shortArg ) + , ShortArgPrefix( shortArgPrefix ) + , ArgHelp( argHelp ) + , ArgLabel( argLabel ) + , ArgGroup( argGroup ) + , ArgGroupDescription( groupDescription ) + , IgnoreRest( ignoreRest ) + , NumberOfParametersToProcess( 0 ) + , Deprecated( deprecated ) + , Optional( optional ) + , DefaultValue( defaultValue ) + , Value( type ) + , ValueType( type ) + { + Value = defaultValue; + + switch ( type ) + { + case mitkCommandLineParser::String: + { + NumberOfParametersToProcess = 1; + } + break; + case mitkCommandLineParser::Bool: + { + NumberOfParametersToProcess = 0; + } + break; + case mitkCommandLineParser::StringList: + { + NumberOfParametersToProcess = -1; + } + break; + case mitkCommandLineParser::Int: + { + NumberOfParametersToProcess = 1; + } + break; + case mitkCommandLineParser::Float: + { + NumberOfParametersToProcess = 1; + } + break; + + case mitkCommandLineParser::OutputDirectory: + case mitkCommandLineParser::InputDirectory: + { + NumberOfParametersToProcess = 1; + } + break; + + case mitkCommandLineParser::OutputFile: + case mitkCommandLineParser::InputFile: + { + NumberOfParametersToProcess = 1; + } + break; + case mitkCommandLineParser::InputImage: + { + NumberOfParametersToProcess = 1; + } + break; + + default: + std::cout << "Type not supported: " << static_cast( type ); + } + } + + ~CommandLineParserArgumentDescription() {} + bool addParameter( const string& value ); + + string helpText(); + + string LongArg; + string LongArgPrefix; + string ShortArg; + string ShortArgPrefix; + string ArgHelp; + string ArgLabel; + string ArgGroup; + string ArgGroupDescription; + bool IgnoreRest; + int NumberOfParametersToProcess; + bool Deprecated; + bool Optional; + + us::Any DefaultValue; + us::Any Value; + mitkCommandLineParser::Type ValueType; +}; + +// -------------------------------------------------------------------------- +bool CommandLineParserArgumentDescription::addParameter( const string& value ) +{ + switch ( ValueType ) + { + case mitkCommandLineParser::String: + { + Value = value; + } + break; + case mitkCommandLineParser::Bool: + { + if ( value.compare( "true" ) == 0 ) + Value = true; + else + Value = false; + } + break; + case mitkCommandLineParser::StringList: + { + try + { + mitkCommandLineParser::StringContainerType list = + us::any_cast( Value ); + list.push_back( value ); + Value = list; + } + catch ( ... ) + { + mitkCommandLineParser::StringContainerType list; + list.push_back( value ); + Value = list; + } + } + break; + case mitkCommandLineParser::Int: + { + stringstream ss( value ); + int i; + ss >> i; + Value = i; + } + break; + case mitkCommandLineParser::Float: + { + stringstream ss( value ); + float f; + ss >> f; + Value = f; + } + break; + + case mitkCommandLineParser::InputDirectory: + case mitkCommandLineParser::OutputDirectory: + { + Value = value; + } + break; + + case mitkCommandLineParser::InputFile: + case mitkCommandLineParser::InputImage: + case mitkCommandLineParser::OutputFile: + { + Value = value; + } + break; + + default: + return false; + } + + return true; +} + +// -------------------------------------------------------------------------- +string CommandLineParserArgumentDescription::helpText() +{ + string text; + + string shortAndLongArg; + if ( !this->ShortArg.empty() ) + { + shortAndLongArg = " "; + shortAndLongArg += this->ShortArgPrefix; + shortAndLongArg += this->ShortArg; + } + + if ( !this->LongArg.empty() ) + { + if ( this->ShortArg.empty() ) + shortAndLongArg.append( " " ); + else + shortAndLongArg.append( ", " ); + + shortAndLongArg += this->LongArgPrefix; + shortAndLongArg += this->LongArg; + } + + text = text + shortAndLongArg + ", " + this->ArgHelp; + + if ( this->Optional ) + text += " (optional)"; + + if ( !this->DefaultValue.Empty() ) + { + text = text + ", (default: " + this->DefaultValue.ToString() + ")"; + } + text += "\n"; + return text; +} +} + +// -------------------------------------------------------------------------- +// ctkCommandLineParser::ctkInternal class + +// -------------------------------------------------------------------------- +class mitkCommandLineParser::ctkInternal +{ +public: + ctkInternal() + : Debug( false ) + , FieldWidth( 0 ) + , StrictMode( false ) + { + } + + ~ctkInternal() {} + CommandLineParserArgumentDescription* argumentDescription( const string& argument ); + + vector ArgumentDescriptionList; + map ArgNameToArgumentDescriptionMap; + map> GroupToArgumentDescriptionListMap; + + StringContainerType UnparsedArguments; + StringContainerType ProcessedArguments; + string ErrorString; + bool Debug; + string::size_type FieldWidth; + string LongPrefix; + string ShortPrefix; + string CurrentGroup; + string DisableQSettingsLongArg; + string DisableQSettingsShortArg; + bool StrictMode; +}; + +// -------------------------------------------------------------------------- +// ctkCommandLineParser::ctkInternal methods + +// -------------------------------------------------------------------------- +CommandLineParserArgumentDescription* mitkCommandLineParser::ctkInternal::argumentDescription( const string& argument ) +{ + string unprefixedArg = argument; + + if ( !LongPrefix.empty() && argument.compare( 0, LongPrefix.size(), LongPrefix ) == 0 ) + { + // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix + if ( argument == LongPrefix && !ShortPrefix.empty() && argument.compare( 0, ShortPrefix.size(), ShortPrefix ) == 0 ) + { + unprefixedArg = argument.substr( ShortPrefix.size(), argument.size() ); + } + else + { + unprefixedArg = argument.substr( LongPrefix.size(), argument.size() ); + } + } + else if ( !ShortPrefix.empty() && argument.compare( 0, ShortPrefix.size(), ShortPrefix ) == 0 ) + { + unprefixedArg = argument.substr( ShortPrefix.size(), argument.size() ); + } + else if ( !LongPrefix.empty() && !ShortPrefix.empty() ) + { + return nullptr; + } + + if ( ArgNameToArgumentDescriptionMap.count( unprefixedArg ) ) + { + return this->ArgNameToArgumentDescriptionMap[ unprefixedArg ]; + } + return nullptr; +} + +// -------------------------------------------------------------------------- +// ctkCommandLineParser methods + +// -------------------------------------------------------------------------- +mitkCommandLineParser::mitkCommandLineParser() +{ + this->Internal = new ctkInternal(); + this->Category = string(); + this->Title = string(); + this->Contributor = string(); + this->Description = string(); + this->ParameterGroupName = "Parameters"; + this->ParameterGroupDescription = "Parameters"; +} + +// -------------------------------------------------------------------------- +mitkCommandLineParser::~mitkCommandLineParser() +{ + delete this->Internal; +} + +// -------------------------------------------------------------------------- +map mitkCommandLineParser::parseArguments( const StringContainerType& arguments, bool* ok ) +{ + // Reset + this->Internal->UnparsedArguments.clear(); + this->Internal->ProcessedArguments.clear(); + this->Internal->ErrorString.clear(); + // foreach (CommandLineParserArgumentDescription* desc, this->Internal->ArgumentDescriptionList) + for ( unsigned int i = 0; i < Internal->ArgumentDescriptionList.size(); i++ ) + { + CommandLineParserArgumentDescription* desc = Internal->ArgumentDescriptionList.at( i ); + desc->Value = us::Any( desc->ValueType ); + if ( !desc->DefaultValue.Empty() ) + { + desc->Value = desc->DefaultValue; + } + } + bool error = false; + bool ignoreRest = false; + CommandLineParserArgumentDescription* currentArgDesc = nullptr; + vector parsedArgDescriptions; + for ( unsigned int i = 1; i < arguments.size(); ++i ) + { + string argument = arguments.at( i ); + + if ( this->Internal->Debug ) + { + std::cout << "Processing" << argument; + } + if ( !argument.compare( "--xml" ) || !argument.compare( "-xml" ) || !argument.compare( "--XML" ) || + !argument.compare( "-XML" ) ) + { + this->generateXmlOutput(); + return map(); + } + + // should argument be ignored ? + if ( ignoreRest ) + { + if ( this->Internal->Debug ) + { + std::cout << " Skipping: IgnoreRest flag was been set"; + } + this->Internal->UnparsedArguments.push_back( argument ); + continue; + } + + // Skip if the argument does not start with the defined prefix + if ( !( argument.compare( 0, Internal->LongPrefix.size(), Internal->LongPrefix ) == 0 || + argument.compare( 0, Internal->ShortPrefix.size(), Internal->ShortPrefix ) == 0 ) ) + { + if ( this->Internal->StrictMode ) + { + this->Internal->ErrorString = "Unknown argument "; + this->Internal->ErrorString += argument; + error = true; + break; + } + if ( this->Internal->Debug ) + { + std::cout << " Skipping: It does not start with the defined prefix"; + } + this->Internal->UnparsedArguments.push_back( argument ); + continue; + } + + // Skip if argument has already been parsed ... + bool alreadyProcessed = false; + for ( auto alreadyHandledArgument : Internal->ProcessedArguments ) + if ( argument.compare( alreadyHandledArgument ) == 0 ) + { + alreadyProcessed = true; + break; + } + + if ( alreadyProcessed ) + { + if ( this->Internal->StrictMode ) + { + this->Internal->ErrorString = "Argument "; + this->Internal->ErrorString += argument; + this->Internal->ErrorString += " already processed !"; + error = true; + break; + } + if ( this->Internal->Debug ) + { + std::cout << " Skipping: Already processed !"; + } + continue; + } + + // Retrieve corresponding argument description + currentArgDesc = this->Internal->argumentDescription( argument ); + + // Is there a corresponding argument description ? + if ( currentArgDesc ) + { + // If the argument is deprecated, print the help text but continue processing + if ( currentArgDesc->Deprecated ) + { + std::cout << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; + } + else + { + parsedArgDescriptions.push_back( currentArgDesc ); + } + + this->Internal->ProcessedArguments.push_back( currentArgDesc->ShortArg ); + this->Internal->ProcessedArguments.push_back( currentArgDesc->LongArg ); + int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; + ignoreRest = currentArgDesc->IgnoreRest; + if ( this->Internal->Debug && ignoreRest ) + { + std::cout << " IgnoreRest flag is True"; + } + + // Is the number of parameters associated with the argument being processed known ? + if ( numberOfParametersToProcess == 0 ) + { + currentArgDesc->addParameter( "true" ); + } + else if ( numberOfParametersToProcess > 0 ) + { + string missingParameterError = "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; + for ( int j = 1; j <= numberOfParametersToProcess; ++j ) + { + if ( i + j >= arguments.size() ) + { + // this->Internal->ErrorString = + // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); + // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } + if ( ok ) + { + *ok = false; + } + return map(); + } + string parameter = arguments.at( i + j ); + if ( this->Internal->Debug ) + { + std::cout << " Processing parameter" << j << ", value:" << parameter; + } + if ( this->argumentAdded( parameter ) ) + { + // this->Internal->ErrorString = + // missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); + // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } + if ( ok ) + { + *ok = false; + } + return map(); + } + if ( !currentArgDesc->addParameter( parameter ) ) + { + // this->Internal->ErrorString = string( + // "Value(s) associated with argument %1 are incorrect. %2"). + // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); + // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } + if ( ok ) + { + *ok = false; + } + return map(); + } + } + // Update main loop increment + i = i + numberOfParametersToProcess; + } + else if ( numberOfParametersToProcess == -1 ) + { + if ( this->Internal->Debug ) + { + std::cout << " Proccessing StringList ..."; + } + int j = 1; + while ( j + i < arguments.size() ) + { + if ( this->argumentAdded( arguments.at( j + i ) ) ) + { + if ( this->Internal->Debug ) + { + std::cout << " No more parameter for" << argument; + } + break; + } + string parameter = arguments.at( j + i ); + + if ( parameter.compare( 0, Internal->LongPrefix.size(), Internal->LongPrefix ) == 0 || + parameter.compare( 0, Internal->ShortPrefix.size(), Internal->ShortPrefix ) == 0 ) + { + j--; + break; + } + + if ( this->Internal->Debug ) + { + std::cout << " Processing parameter" << j << ", value:" << parameter; + } + if ( !currentArgDesc->addParameter( parameter ) ) + { + // this->Internal->ErrorString = string( + // "Value(s) associated with argument %1 are incorrect. %2"). + // arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); + // if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } + if ( ok ) + { + *ok = false; + } + return map(); + } + j++; + } + // Update main loop increment + i = i + j; + } + } + else + { + if ( this->Internal->StrictMode ) + { + this->Internal->ErrorString = "Unknown argument "; + this->Internal->ErrorString += argument; + error = true; + break; + } + if ( this->Internal->Debug ) + { + std::cout << " Skipping: Unknown argument"; + } + this->Internal->UnparsedArguments.push_back( argument ); + } + } + + if ( ok ) + { + *ok = !error; + } + + map parsedArguments; + + int obligatoryArgs = 0; + vector::iterator it; + for ( it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end(); ++it ) + { + CommandLineParserArgumentDescription* desc = *it; + + if ( !desc->Optional ) + obligatoryArgs++; + } + + int parsedObligatoryArgs = 0; + for ( it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end(); ++it ) + { + CommandLineParserArgumentDescription* desc = *it; + + string key; + if ( !desc->LongArg.empty() ) + { + key = desc->LongArg; + } + else + { + key = desc->ShortArg; + } + + if ( !desc->Optional ) + parsedObligatoryArgs++; + + std::pair elem; + elem.first = key; + elem.second = desc->Value; + parsedArguments.insert( elem ); + } + + if ( obligatoryArgs > parsedObligatoryArgs ) + { + parsedArguments.clear(); + cout << helpText(); + } + + return parsedArguments; +} + +// ------------------------------------------------------------------------- +map mitkCommandLineParser::parseArguments( int argc, char** argv, bool* ok ) +{ + StringContainerType arguments; + + // Create a StringContainerType of arguments + for ( int i = 0; i < argc; ++i ) + arguments.push_back( argv[ i ] ); + + return this->parseArguments( arguments, ok ); +} + +// ------------------------------------------------------------------------- +string mitkCommandLineParser::errorString() const +{ + return this->Internal->ErrorString; +} + +// ------------------------------------------------------------------------- +const mitkCommandLineParser::StringContainerType& mitkCommandLineParser::unparsedArguments() const +{ + return this->Internal->UnparsedArguments; +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::addArgument( const string& longarg, + const string& shortarg, + Type type, + const string& argLabel, + const string& argHelp, + const us::Any& defaultValue, + bool optional, + bool ignoreRest, + bool deprecated ) +{ + if ( longarg.empty() && shortarg.empty() ) + { + return; + } + + /* Make sure it's not already added */ + bool added = ( this->Internal->ArgNameToArgumentDescriptionMap.count( longarg ) != 0 ); + if ( added ) + { + return; + } + + added = ( this->Internal->ArgNameToArgumentDescriptionMap.count( shortarg ) != 0 ); + if ( added ) + { + return; + } + + auto argDesc = new CommandLineParserArgumentDescription( longarg, + this->Internal->LongPrefix, + shortarg, + this->Internal->ShortPrefix, + type, + argHelp, + argLabel, + defaultValue, + ignoreRest, + deprecated, + optional, + ParameterGroupName, + ParameterGroupDescription ); + + std::string::size_type argWidth = 0; + if ( !longarg.empty() ) + { + this->Internal->ArgNameToArgumentDescriptionMap[ longarg ] = argDesc; + argWidth += longarg.size() + this->Internal->LongPrefix.size(); + } + if ( !shortarg.empty() ) + { + this->Internal->ArgNameToArgumentDescriptionMap[ shortarg ] = argDesc; + argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2; + } + argWidth += 5; + + // Set the field width for the arguments + if ( argWidth > this->Internal->FieldWidth ) + { + this->Internal->FieldWidth = argWidth; + } + + this->Internal->ArgumentDescriptionList.push_back( argDesc ); + this->Internal->GroupToArgumentDescriptionListMap[ this->Internal->CurrentGroup ].push_back( argDesc ); +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::addDeprecatedArgument( const string& longarg, + const string& shortarg, + const string& argLabel, + const string& argHelp ) +{ + addArgument( longarg, shortarg, StringList, argLabel, argHelp, us::Any(), false, true, false ); +} + +// -------------------------------------------------------------------------- +std::string::size_type mitkCommandLineParser::fieldWidth() const +{ + return this->Internal->FieldWidth; +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::beginGroup( const string& description ) +{ + this->Internal->CurrentGroup = description; +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::endGroup() +{ + this->Internal->CurrentGroup.clear(); +} + +// -------------------------------------------------------------------------- +string mitkCommandLineParser::helpText() const +{ + string text; + vector deprecatedArgs; + + // Loop over grouped argument descriptions + map>::iterator it; + for ( it = Internal->GroupToArgumentDescriptionListMap.begin(); + it != Internal->GroupToArgumentDescriptionListMap.end(); + ++it ) + { + if ( !( *it ).first.empty() ) + { + text = text + "\n" + ( *it ).first + "\n"; + } + + vector::iterator it2; + for ( it2 = ( *it ).second.begin(); it2 != ( *it ).second.end(); ++it2 ) + { + CommandLineParserArgumentDescription* argDesc = *it2; + if ( argDesc->Deprecated ) + { + deprecatedArgs.push_back( argDesc ); + } + else + { + text += argDesc->helpText(); + } + } + } + + if ( !deprecatedArgs.empty() ) + { + text += "\nDeprecated arguments:\n"; + vector::iterator it2; + for ( it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2 ) + { + CommandLineParserArgumentDescription* argDesc = *it2; + text += argDesc->helpText(); + } + } + + return text; +} + +// -------------------------------------------------------------------------- +bool mitkCommandLineParser::argumentAdded( const string& argument ) const +{ + return ( this->Internal->ArgNameToArgumentDescriptionMap.count( argument ) != 0 ); +} + +// -------------------------------------------------------------------------- +bool mitkCommandLineParser::argumentParsed( const string& argument ) const +{ + for ( unsigned int i = 0; i < Internal->ProcessedArguments.size(); i++ ) + if ( argument.compare( Internal->ProcessedArguments.at( i ) ) == 0 ) + return true; + return false; +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::setArgumentPrefix( const string& longPrefix, const string& shortPrefix ) +{ + this->Internal->LongPrefix = longPrefix; + this->Internal->ShortPrefix = shortPrefix; +} + +// -------------------------------------------------------------------------- +void mitkCommandLineParser::setStrictModeEnabled( bool strictMode ) +{ + this->Internal->StrictMode = strictMode; +} + +void mitkCommandLineParser::generateXmlOutput() +{ + std::stringstream xml; + + xml << "" << endl; + xml << "" << Category << "" << endl; + xml << "" << Title << "" << endl; + xml << "" << Description << "" << endl; + xml << "" << Contributor << "" << endl; + xml << "" << endl; + + std::vector::iterator it; + + std::string lastParameterGroup = ""; + for ( it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); + it++ ) + { + std::string type; + switch ( ( *it )->ValueType ) + { + case mitkCommandLineParser::String: + type = "string"; + break; + + case mitkCommandLineParser::Bool: + type = "boolean"; + break; + + case mitkCommandLineParser::StringList: + type = "string-vector"; + break; + + case mitkCommandLineParser::Int: + type = "integer"; + break; + + case mitkCommandLineParser::Float: + type = "float"; + break; + + case mitkCommandLineParser::OutputDirectory: + case mitkCommandLineParser::InputDirectory: + type = "directory"; + break; + + case mitkCommandLineParser::InputImage: + type = "image"; + break; + + case mitkCommandLineParser::OutputFile: + case mitkCommandLineParser::InputFile: + type = "file"; + break; + } + + if ( lastParameterGroup.compare( ( *it )->ArgGroup ) ) + { + if ( it != this->Internal->ArgumentDescriptionList.begin() ) + { + xml << "" << endl; + xml << "" << endl; + } + xml << "" << endl; + xml << "" << ( *it )->ArgGroupDescription << "" << endl; + lastParameterGroup = ( *it )->ArgGroup; + } + + // Skip help item, as it's no use in GUI + if ( ( *it )->ShortArg == "h" ) + continue; + + xml << "<" << type << ">" << endl; + xml << "" << ( *it )->LongArg << "" << endl; + xml << "" << ( *it )->ArgHelp << "" << endl; + xml << "" << endl; + if ( !( *it )->DefaultValue.Empty() ) + xml << "" << ( *it )->DefaultValue.ToString() << "" << endl; + + xml << "" << ( *it )->LongArg << "" << endl; + xml << "" << ( *it )->ShortArg << "" << endl; + + if ( ( *it )->ValueType == mitkCommandLineParser::InputDirectory || + ( *it )->ValueType == mitkCommandLineParser::InputFile || + ( *it )->ValueType == mitkCommandLineParser::InputImage ) + { + xml << "input" << endl; + } + else if ( ( *it )->ValueType == mitkCommandLineParser::OutputDirectory || + ( *it )->ValueType == mitkCommandLineParser::OutputFile ) + { + xml << "output" << endl; + } + xml << "" << endl; + } + + xml << "" << endl; + xml << "" << endl; + + cout << xml.str(); +} + +void mitkCommandLineParser::setTitle( string title ) +{ + Title = title; +} +void mitkCommandLineParser::setContributor( string contributor ) +{ + Contributor = contributor; +} + +void mitkCommandLineParser::setCategory( string category ) +{ + Category = category; +} + +void mitkCommandLineParser::setDescription( string description ) +{ + Description = description; +} + +void mitkCommandLineParser::changeParameterGroup( string name, string tooltip ) +{ + ParameterGroupName = name; + ParameterGroupDescription = tooltip; +} diff --git a/Modules/Core/TestingHelper/include/mitkTestFixture.h b/Modules/Core/TestingHelper/include/mitkTestFixture.h index 6657749b10..2e9f5889eb 100644 --- a/Modules/Core/TestingHelper/include/mitkTestFixture.h +++ b/Modules/Core/TestingHelper/include/mitkTestFixture.h @@ -1,132 +1,132 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) 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 MITKTESTFIXTURE_H #define MITKTESTFIXTURE_H #include #include #include #include #include namespace mitk { /** * \brief Test fixture for parameterized tests * * This class is a drop-in replacement for CppUnit::TextFixture and * enables test methods to access individual parameters. You can also * invoke one method multiple times with different parameters. * * - * The following simple example creates a single test withoud custom + * The following simple example creates a single test without custom * parameters: * * \code * class MySimpleTestSuite : public mitk::TestFixture * { * CPPUNIT_TEST_SUITE(MySimpleTestSuite); * MITK_TEST(FivePlusFiveTest); * CPPUNIT_TEST_SUITE_END(); * * public: * void FivePlusFiveTest() * { * CPPUNIT_ASSERT(5+5 == 10); * } * }; * MITK_TEST_SUITE_REGISTRATION(MySimpleTestSuite) * \endcode * * * The following example creates a test class containing only * one test method, but the associated test suite contains three tests, * using different parameters for each call of the same method. Use * the macro MITK_PARAMETERIZED_TEST_1 only if you know what you are * doing. If you are not sure, use MITK_TEST instead. * * \code * class MyTestSuite : public mitk::TestFixture * { * CPPUNIT_TEST_SUITE(MyTestSuite); * MITK_PARAMETERIZED_TEST_1(TestSomething, "One"); * MITK_PARAMETERIZED_TEST_1(TestSomething, "Two"); * MITK_PARAMETERIZED_TEST_1(TestSomething, "Three"); * CPPUNIT_TEST_SUITE_END(); * * public: * * void TestSomething() * { * std::vector parameter = GetTestParameter(); * CPPUNIT_ASSERT(parameter.size() == 1); * std::string testParam = parameter[0]; * * MITK_INFO << "Parameter: " << testParam; * } * }; * MITK_TEST_SUITE_REGISTRATION(MyTestSuite) * \endcode * * \sa MITK_PARAMETERIZED_TEST * \sa MITK_PARAMETERIZED_TEST_1 */ class TestFixture : public CppUnit::TestFixture { protected: /** * \brief Get parameters for this test fixture * * This method can be called in tests added via the MITK_PARAMETERIZED_TEST * macro or one of its variants. * * \return The list of \c std::string parameters passed to previous calls * of the MITK_PARAMETERIZED_TEST macro or one of its variants. * */ std::vector GetTestParameter() const { return m_Parameter; } /** * \brief Get the absolute path for test data. * * \param testData The realative path in the MITK test data repository. * * \return The absolute path for the test data. */ static std::string GetTestDataFilePath(const std::string& testData) { if (itksys::SystemTools::FileIsFullPath(testData.c_str())) return testData; return std::string(MITK_DATA_DIR) + "/" + testData; } private: template friend class TestCaller; std::vector m_Parameter; }; } #endif // MITKTESTFIXTURE_H diff --git a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt b/Modules/DiffusionImaging/MiniApps/CMakeLists.txt index 84dd09cf5b..a90546cd82 100755 --- a/Modules/DiffusionImaging/MiniApps/CMakeLists.txt +++ b/Modules/DiffusionImaging/MiniApps/CMakeLists.txt @@ -1,128 +1,128 @@ option(BUILD_DiffusionMiniApps "Build commandline tools for diffusion" OFF) if(BUILD_DiffusionMiniApps OR MITK_BUILD_ALL_APPS) find_package(OpenMP) if(NOT OPENMP_FOUND) message("OpenMP is not available.") endif() if(OPENMP_FOUND) message(STATUS "Found OpenMP.") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusionminiapps DwiDenoising^^ ImageResampler^^ NetworkCreation^^MitkFiberTracking_MitkConnectomics NetworkStatistics^^MitkConnectomics ExportShImage^^ Fiberfox^^MitkFiberTracking MultishellMethods^^MitkFiberTracking PeaksAngularError^^MitkFiberTracking PeakExtraction^^MitkFiberTracking FiberExtraction^^MitkFiberTracking FiberProcessing^^MitkFiberTracking FiberDirectionExtraction^^MitkFiberTracking LocalDirectionalFiberPlausibility^^MitkFiberTracking StreamlineTracking^^MitkFiberTracking GibbsTracking^^MitkFiberTracking CopyGeometry^^ DiffusionIndices^^ TractometerMetrics^^MitkFiberTracking QballReconstruction^^ Registration^^ FileFormatConverter^^MitkFiberTracking TensorReconstruction^^ TensorDerivedMapsExtraction^^ DICOMLoader^^ DFTraining^^MitkFiberTracking DFTracking^^MitkFiberTracking ) foreach(diffusionminiapp ${diffusionminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${diffusionminiapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} - DEPENDS MitkCore MitkDiffusionCore ${dependencies_list} + DEPENDS MitkCore MitkDiffusionCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK - CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp + CPP_FILES ${appname}.cpp ) if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(Dicom2Nrrd - DEPENDS MitkCore - CPP_FILES Dicom2Nrrd.cpp mitkCommandLineParser.cpp + DEPENDS MitkCore MitkCommandLine + CPP_FILES Dicom2Nrrd.cpp ) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.cpp b/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.cpp deleted file mode 100755 index 35502e1266..0000000000 --- a/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.cpp +++ /dev/null @@ -1,900 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -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. - -===================================================================*/ -/*========================================================================= - - 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. - -=========================================================================*/ - -// STL includes -#include -#include - - -// MITK includes -#include "mitkCommandLineParser.h" - - -using namespace std; - -namespace -{ -// -------------------------------------------------------------------------- -class CommandLineParserArgumentDescription -{ -public: - - - CommandLineParserArgumentDescription( - const string& longArg, const string& longArgPrefix, - const string& shortArg, const string& shortArgPrefix, - mitkCommandLineParser::Type type, const string& argHelp, const string& argLabel, - const us::Any& defaultValue, bool ignoreRest, - bool deprecated, bool optional, string& argGroup, string& groupDescription) - : LongArg(longArg), LongArgPrefix(longArgPrefix), - ShortArg(shortArg), ShortArgPrefix(shortArgPrefix), - ArgHelp(argHelp), ArgLabel(argLabel), IgnoreRest(ignoreRest), NumberOfParametersToProcess(0), - Deprecated(deprecated), DefaultValue(defaultValue), Value(type), ValueType(type), Optional(optional), ArgGroup(argGroup), ArgGroupDescription(groupDescription) - { - Value = defaultValue; - - switch (type) - { - case mitkCommandLineParser::String: - { - NumberOfParametersToProcess = 1; - } - break; - case mitkCommandLineParser::Bool: - { - NumberOfParametersToProcess = 0; - } - break; - case mitkCommandLineParser::StringList: - { - NumberOfParametersToProcess = -1; - } - break; - case mitkCommandLineParser::Int: - { - NumberOfParametersToProcess = 1; - } - break; - case mitkCommandLineParser::Float: - { - NumberOfParametersToProcess = 1; - } - break; - - case mitkCommandLineParser::OutputDirectory: - case mitkCommandLineParser::InputDirectory: - { - NumberOfParametersToProcess = 1; - } - break; - - case mitkCommandLineParser::OutputFile: - case mitkCommandLineParser::InputFile: - { - NumberOfParametersToProcess = 1; - } - break; - case mitkCommandLineParser::InputImage: - { - NumberOfParametersToProcess = 1; - } - break; - - default: - std::cout << "Type not supported: " << static_cast(type); - } - - } - - ~CommandLineParserArgumentDescription(){} - - bool addParameter(const string& value); - - string helpText(); - - string LongArg; - string LongArgPrefix; - string ShortArg; - string ShortArgPrefix; - string ArgHelp; - string ArgLabel; - string ArgGroup; - string ArgGroupDescription; - bool IgnoreRest; - int NumberOfParametersToProcess; - bool Deprecated; - bool Optional; - - us::Any DefaultValue; - us::Any Value; - mitkCommandLineParser::Type ValueType; -}; - -// -------------------------------------------------------------------------- -bool CommandLineParserArgumentDescription::addParameter(const string &value) -{ - switch (ValueType) - { - case mitkCommandLineParser::String: - { - Value = value; - } - break; - case mitkCommandLineParser::Bool: - { - if (value.compare("true")==0) - Value = true; - else - Value = false; - } - break; - case mitkCommandLineParser::StringList: - { - try - { - mitkCommandLineParser::StringContainerType list = us::any_cast(Value); - list.push_back(value); - Value = list; - } - catch(...) - { - mitkCommandLineParser::StringContainerType list; - list.push_back(value); - Value = list; - } - } - break; - case mitkCommandLineParser::Int: - { - stringstream ss(value); - int i; - ss >> i; - Value = i; - } - break; - case mitkCommandLineParser::Float: - { - stringstream ss(value); - float f; - ss >> f; - Value = f; - } - break; - - case mitkCommandLineParser::InputDirectory: - case mitkCommandLineParser::OutputDirectory: - { - Value = value; - } - break; - - case mitkCommandLineParser::InputFile: - case mitkCommandLineParser::InputImage: - case mitkCommandLineParser::OutputFile: - { - Value = value; - } - break; - - default: - return false; - } - - return true; -} - -// -------------------------------------------------------------------------- -string CommandLineParserArgumentDescription::helpText() -{ - string text; - - string shortAndLongArg; - if (!this->ShortArg.empty()) - { - shortAndLongArg = " "; - shortAndLongArg += this->ShortArgPrefix; - shortAndLongArg += this->ShortArg; - } - - if (!this->LongArg.empty()) - { - if (this->ShortArg.empty()) - shortAndLongArg.append(" "); - else - shortAndLongArg.append(", "); - - shortAndLongArg += this->LongArgPrefix; - shortAndLongArg += this->LongArg; - } - - text = text + shortAndLongArg + ", " + this->ArgHelp; - - if (this->Optional) - text += " (optional)"; - - if (!this->DefaultValue.Empty()) - { - text = text + ", (default: " + this->DefaultValue.ToString() + ")"; - } - text += "\n"; - return text; -} - -} - -// -------------------------------------------------------------------------- -// ctkCommandLineParser::ctkInternal class - -// -------------------------------------------------------------------------- -class mitkCommandLineParser::ctkInternal -{ -public: - ctkInternal() - : Debug(false), FieldWidth(0), StrictMode(false) - {} - - ~ctkInternal() { } - - CommandLineParserArgumentDescription* argumentDescription(const string& argument); - - vector ArgumentDescriptionList; - map ArgNameToArgumentDescriptionMap; - map > GroupToArgumentDescriptionListMap; - - StringContainerType UnparsedArguments; - StringContainerType ProcessedArguments; - string ErrorString; - bool Debug; - int FieldWidth; - string LongPrefix; - string ShortPrefix; - string CurrentGroup; - string DisableQSettingsLongArg; - string DisableQSettingsShortArg; - bool StrictMode; -}; - -// -------------------------------------------------------------------------- -// ctkCommandLineParser::ctkInternal methods - -// -------------------------------------------------------------------------- -CommandLineParserArgumentDescription* -mitkCommandLineParser::ctkInternal::argumentDescription(const string& argument) -{ - string unprefixedArg = argument; - - if (!LongPrefix.empty() && argument.compare(0, LongPrefix.size(), LongPrefix)==0) - { - // Case when (ShortPrefix + UnPrefixedArgument) matches LongPrefix - if (argument == LongPrefix && !ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix)==0) - { - unprefixedArg = argument.substr(ShortPrefix.size(),argument.size()); - } - else - { - unprefixedArg = argument.substr(LongPrefix.size(),argument.size()); - } - } - else if (!ShortPrefix.empty() && argument.compare(0, ShortPrefix.size(), ShortPrefix)==0) - { - unprefixedArg = argument.substr(ShortPrefix.size(),argument.size()); - } - else if (!LongPrefix.empty() && !ShortPrefix.empty()) - { - return nullptr; - } - - if (ArgNameToArgumentDescriptionMap.count(unprefixedArg)) - { - return this->ArgNameToArgumentDescriptionMap[unprefixedArg]; - } - return nullptr; -} - -// -------------------------------------------------------------------------- -// ctkCommandLineParser methods - -// -------------------------------------------------------------------------- -mitkCommandLineParser::mitkCommandLineParser() -{ - this->Internal = new ctkInternal(); - this->Category = string(); - this->Title = string(); - this->Contributor = string(); - this->Description = string(); - this->ParameterGroupName = "Parameters"; - this->ParameterGroupDescription = "Parameters"; -} - -// -------------------------------------------------------------------------- -mitkCommandLineParser::~mitkCommandLineParser() -{ - delete this->Internal; -} - -// -------------------------------------------------------------------------- -map mitkCommandLineParser::parseArguments(const StringContainerType& arguments, - bool* ok) -{ - // Reset - this->Internal->UnparsedArguments.clear(); - this->Internal->ProcessedArguments.clear(); - this->Internal->ErrorString.clear(); - // foreach (CommandLineParserArgumentDescription* desc, this->Internal->ArgumentDescriptionList) - for (unsigned int i=0; iArgumentDescriptionList.size(); i++) - { - CommandLineParserArgumentDescription* desc = Internal->ArgumentDescriptionList.at(i); - desc->Value = us::Any(desc->ValueType); - if (!desc->DefaultValue.Empty()) - { - desc->Value = desc->DefaultValue; - } - } - bool error = false; - bool ignoreRest = false; - CommandLineParserArgumentDescription * currentArgDesc = nullptr; - vector parsedArgDescriptions; - for(unsigned int i = 1; i < arguments.size(); ++i) - { - string argument = arguments.at(i); - - if (this->Internal->Debug) { std::cout << "Processing" << argument; } - if (!argument.compare("--xml") || !argument.compare("-xml") || !argument.compare("--XML") || !argument.compare("-XML")) - { - this->generateXmlOutput(); - return map(); - } - - // should argument be ignored ? - if (ignoreRest) - { - if (this->Internal->Debug) - { - std::cout << " Skipping: IgnoreRest flag was been set"; - } - this->Internal->UnparsedArguments.push_back(argument); - continue; - } - - // Skip if the argument does not start with the defined prefix - if (!(argument.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix)==0 - || argument.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix)==0)) - { - if (this->Internal->StrictMode) - { - this->Internal->ErrorString = "Unknown argument "; - this->Internal->ErrorString += argument; - error = true; - break; - } - if (this->Internal->Debug) - { - std::cout << " Skipping: It does not start with the defined prefix"; - } - this->Internal->UnparsedArguments.push_back(argument); - continue; - } - - // Skip if argument has already been parsed ... - bool alreadyProcessed = false; - for (unsigned int i=0; iProcessedArguments.size(); i++) - if (argument.compare(Internal->ProcessedArguments.at(i))==0) - { - alreadyProcessed = true; - break; - } - - if (alreadyProcessed) - { - if (this->Internal->StrictMode) - { - this->Internal->ErrorString = "Argument "; - this->Internal->ErrorString += argument; - this->Internal->ErrorString += " already processed !"; - error = true; - break; - } - if (this->Internal->Debug) - { - std::cout << " Skipping: Already processed !"; - } - continue; - } - - // Retrieve corresponding argument description - currentArgDesc = this->Internal->argumentDescription(argument); - - // Is there a corresponding argument description ? - if (currentArgDesc) - { - // If the argument is deprecated, print the help text but continue processing - if (currentArgDesc->Deprecated) - { - std::cout << "Deprecated argument " << argument << ": " << currentArgDesc->ArgHelp; - } - else - { - parsedArgDescriptions.push_back(currentArgDesc); - } - - this->Internal->ProcessedArguments.push_back(currentArgDesc->ShortArg); - this->Internal->ProcessedArguments.push_back(currentArgDesc->LongArg); - int numberOfParametersToProcess = currentArgDesc->NumberOfParametersToProcess; - ignoreRest = currentArgDesc->IgnoreRest; - if (this->Internal->Debug && ignoreRest) - { - std::cout << " IgnoreRest flag is True"; - } - - // Is the number of parameters associated with the argument being processed known ? - if (numberOfParametersToProcess == 0) - { - currentArgDesc->addParameter("true"); - } - else if (numberOfParametersToProcess > 0) - { - string missingParameterError = - "Argument %1 has %2 value(s) associated whereas exacly %3 are expected."; - for(int j=1; j <= numberOfParametersToProcess; ++j) - { - if (i + j >= arguments.size()) - { -// this->Internal->ErrorString = -// missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); -// if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } - if (ok) { *ok = false; } - return map(); - } - string parameter = arguments.at(i + j); - if (this->Internal->Debug) - { - std::cout << " Processing parameter" << j << ", value:" << parameter; - } - if (this->argumentAdded(parameter)) - { -// this->Internal->ErrorString = -// missingParameterError.arg(argument).arg(j-1).arg(numberOfParametersToProcess); -// if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } - if (ok) { *ok = false; } - return map(); - } - if (!currentArgDesc->addParameter(parameter)) - { -// this->Internal->ErrorString = string( -// "Value(s) associated with argument %1 are incorrect. %2"). -// arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); -// if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } - if (ok) { *ok = false; } - return map(); - } - } - // Update main loop increment - i = i + numberOfParametersToProcess; - } - else if (numberOfParametersToProcess == -1) - { - if (this->Internal->Debug) - { - std::cout << " Proccessing StringList ..."; - } - int j = 1; - while(j + i < arguments.size()) - { - if (this->argumentAdded(arguments.at(j + i))) - { - if (this->Internal->Debug) - { - std::cout << " No more parameter for" << argument; - } - break; - } - string parameter = arguments.at(j + i); - - if (parameter.compare(0, Internal->LongPrefix.size(), Internal->LongPrefix)==0 - || parameter.compare(0, Internal->ShortPrefix.size(), Internal->ShortPrefix)==0) - { - j--; - break; - } - - if (this->Internal->Debug) - { - std::cout << " Processing parameter" << j << ", value:" << parameter; - } - if (!currentArgDesc->addParameter(parameter)) - { -// this->Internal->ErrorString = string( -// "Value(s) associated with argument %1 are incorrect. %2"). -// arg(argument).arg(currentArgDesc->ExactMatchFailedMessage); -// if (this->Internal->Debug) { std::cout << this->Internal->ErrorString; } - if (ok) { *ok = false; } - return map(); - } - j++; - } - // Update main loop increment - i = i + j; - } - } - else - { - if (this->Internal->StrictMode) - { - this->Internal->ErrorString = "Unknown argument "; - this->Internal->ErrorString += argument; - error = true; - break; - } - if (this->Internal->Debug) - { - std::cout << " Skipping: Unknown argument"; - } - this->Internal->UnparsedArguments.push_back(argument); - } - } - - if (ok) - { - *ok = !error; - } - - map parsedArguments; - - int obligatoryArgs = 0; - vector::iterator it; - for(it = Internal->ArgumentDescriptionList.begin(); it != Internal->ArgumentDescriptionList.end();++it) - { - CommandLineParserArgumentDescription* desc = *it; - - if(!desc->Optional) - obligatoryArgs++; - } - - int parsedObligatoryArgs = 0; - for(it = parsedArgDescriptions.begin(); it != parsedArgDescriptions.end();++it) - { - CommandLineParserArgumentDescription* desc = *it; - - string key; - if (!desc->LongArg.empty()) - { - key = desc->LongArg; - } - else - { - key = desc->ShortArg; - } - - if(!desc->Optional) - parsedObligatoryArgs++; - - std::pair elem; elem.first = key; elem.second = desc->Value; - parsedArguments.insert(elem); - } - - if (obligatoryArgs>parsedObligatoryArgs) - { - parsedArguments.clear(); - cout << helpText(); - } - - return parsedArguments; -} - -// ------------------------------------------------------------------------- -map mitkCommandLineParser::parseArguments(int argc, char** argv, bool* ok) -{ - StringContainerType arguments; - - // Create a StringContainerType of arguments - for(int i = 0; i < argc; ++i) - arguments.push_back(argv[i]); - - return this->parseArguments(arguments, ok); -} - -// ------------------------------------------------------------------------- -string mitkCommandLineParser::errorString() const -{ - return this->Internal->ErrorString; -} - -// ------------------------------------------------------------------------- -const mitkCommandLineParser::StringContainerType& mitkCommandLineParser::unparsedArguments() const -{ - return this->Internal->UnparsedArguments; -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::addArgument(const string& longarg, const string& shortarg, - Type type, const string& argLabel, const string& argHelp, - const us::Any &defaultValue, bool optional, bool ignoreRest, - bool deprecated) -{ - if (longarg.empty() && shortarg.empty()) { return; } - - /* Make sure it's not already added */ - bool added = this->Internal->ArgNameToArgumentDescriptionMap.count(longarg); - if (added) { return; } - - added = this->Internal->ArgNameToArgumentDescriptionMap.count(shortarg); - if (added) { return; } - - auto argDesc = - new CommandLineParserArgumentDescription(longarg, this->Internal->LongPrefix, - shortarg, this->Internal->ShortPrefix, type, - argHelp, argLabel, defaultValue, ignoreRest, deprecated, optional, ParameterGroupName, ParameterGroupDescription); - - int argWidth = 0; - if (!longarg.empty()) - { - this->Internal->ArgNameToArgumentDescriptionMap[longarg] = argDesc; - argWidth += longarg.size() + this->Internal->LongPrefix.size(); - } - if (!shortarg.empty()) - { - this->Internal->ArgNameToArgumentDescriptionMap[shortarg] = argDesc; - argWidth += shortarg.size() + this->Internal->ShortPrefix.size() + 2; - } - argWidth += 5; - - // Set the field width for the arguments - if (argWidth > this->Internal->FieldWidth) - { - this->Internal->FieldWidth = argWidth; - } - - this->Internal->ArgumentDescriptionList.push_back(argDesc); - this->Internal->GroupToArgumentDescriptionListMap[this->Internal->CurrentGroup].push_back(argDesc); -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::addDeprecatedArgument( - const string& longarg, const string& shortarg, const string& argLabel, const string& argHelp) -{ - addArgument(longarg, shortarg, StringList, argLabel, argHelp, us::Any(), false, true, false); -} - -// -------------------------------------------------------------------------- -int mitkCommandLineParser::fieldWidth() const -{ - return this->Internal->FieldWidth; -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::beginGroup(const string& description) -{ - this->Internal->CurrentGroup = description; -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::endGroup() -{ - this->Internal->CurrentGroup.clear(); -} - -// -------------------------------------------------------------------------- -string mitkCommandLineParser::helpText() const -{ - string text; - vector deprecatedArgs; - - // Loop over grouped argument descriptions - map >::iterator it; - for(it = Internal->GroupToArgumentDescriptionListMap.begin(); it != Internal->GroupToArgumentDescriptionListMap.end();++it) - { - if (!(*it).first.empty()) - { - text = text + "\n" + (*it).first + "\n"; - } - - vector::iterator it2; - for(it2 = (*it).second.begin(); it2 != (*it).second.end(); ++it2) - { - CommandLineParserArgumentDescription* argDesc = *it2; - if (argDesc->Deprecated) - { - deprecatedArgs.push_back(argDesc); - } - else - { - text += argDesc->helpText(); - } - } - } - - if (!deprecatedArgs.empty()) - { - text += "\nDeprecated arguments:\n"; - vector::iterator it2; - for(it2 = deprecatedArgs.begin(); it2 != deprecatedArgs.end(); ++it2) - { - CommandLineParserArgumentDescription* argDesc = *it2; - text += argDesc->helpText(); - } - } - - return text; -} - -// -------------------------------------------------------------------------- -bool mitkCommandLineParser::argumentAdded(const string& argument) const -{ - return this->Internal->ArgNameToArgumentDescriptionMap.count(argument); -} - -// -------------------------------------------------------------------------- -bool mitkCommandLineParser::argumentParsed(const string& argument) const -{ - for (unsigned int i=0; iProcessedArguments.size(); i++) - if (argument.compare(Internal->ProcessedArguments.at(i))==0) - return true; - return false; -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::setArgumentPrefix(const string& longPrefix, const string& shortPrefix) -{ - this->Internal->LongPrefix = longPrefix; - this->Internal->ShortPrefix = shortPrefix; -} - -// -------------------------------------------------------------------------- -void mitkCommandLineParser::setStrictModeEnabled(bool strictMode) -{ - this->Internal->StrictMode = strictMode; -} - -void mitkCommandLineParser::generateXmlOutput() -{ - std::stringstream xml; - - xml << "" << endl; - xml << "" << Category << "" << endl; - xml << "" << Title <<"" << endl; - xml << "" << Description << "" << endl; - xml << "" << Contributor << "" << endl; - xml << "" << endl; - - std::vector::iterator it; - - std::string lastParameterGroup = ""; - for (it = this->Internal->ArgumentDescriptionList.begin(); it != this->Internal->ArgumentDescriptionList.end(); it++) - { - std::string type; - switch ((*it)->ValueType) - { - case mitkCommandLineParser::String: - type = "string"; - break; - - case mitkCommandLineParser::Bool: - type = "boolean"; - break; - - case mitkCommandLineParser::StringList: - type = "string-vector"; - break; - - case mitkCommandLineParser::Int: - type = "integer"; - break; - - case mitkCommandLineParser::Float: - type = "float"; - break; - - case mitkCommandLineParser::OutputDirectory: - case mitkCommandLineParser::InputDirectory: - type = "directory"; - break; - - case mitkCommandLineParser::InputImage: - type = "image"; - break; - - case mitkCommandLineParser::OutputFile: - case mitkCommandLineParser::InputFile: - type = "file"; - break; - } - - if (lastParameterGroup.compare((*it)->ArgGroup)) - { - if (it != this->Internal->ArgumentDescriptionList.begin()) - { - xml << "" << endl; - xml << "" << endl; - } - xml << "" << endl; - xml << "" << (*it)->ArgGroupDescription << "" << endl; - lastParameterGroup = (*it)->ArgGroup; - } - - // Skip help item, as it's no use in GUI - if ((*it)->ShortArg == "h") - continue; - - xml << "<" << type << ">" << endl; - xml << "" << (*it)->LongArg << "" << endl; - xml << "" << (*it)->ArgHelp << "" << endl; - xml << "" << endl; - if (!(*it)->DefaultValue.Empty()) - xml << "" << (*it)->DefaultValue.ToString() << "" << endl; - - xml << "" << (*it)->LongArg << "" << endl; - xml << "" << (*it)->ShortArg << "" << endl; - - if ((*it)->ValueType == mitkCommandLineParser::InputDirectory || (*it)->ValueType == mitkCommandLineParser::InputFile || (*it)->ValueType == mitkCommandLineParser::InputImage) - { - xml << "input" << endl; - } - else if ((*it)->ValueType == mitkCommandLineParser::OutputDirectory || (*it)->ValueType == mitkCommandLineParser::OutputFile) - { - xml << "output" << endl; - } - xml << "" << endl; - } - - xml << "" << endl; - xml << "" << endl; - - cout << xml.str(); -} - -void mitkCommandLineParser::setTitle(string title) -{ - Title = title; -} -void mitkCommandLineParser::setContributor(string contributor) -{ - Contributor = contributor; -} - -void mitkCommandLineParser::setCategory(string category) -{ - Category = category; -} - -void mitkCommandLineParser::setDescription(string description) -{ - Description = description; -} - -void mitkCommandLineParser::changeParameterGroup(string name, string tooltip) -{ - ParameterGroupName = name; - ParameterGroupDescription = tooltip; -} diff --git a/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.h b/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.h deleted file mode 100755 index 96e63d9a1d..0000000000 --- a/Modules/DiffusionImaging/MiniApps/mitkCommandLineParser.h +++ /dev/null @@ -1,475 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -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. - -===================================================================*/ -/*========================================================================= - - 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 __mitkCommandLineParser_h -#define __mitkCommandLineParser_h - -#include -#include - - -/** - * \ingroup Core - * - * The CTK command line parser. - * - * Use this class to add information about the command line arguments - * your program understands and to easily parse them from a given list - * of strings. - * - * This parser provides the following features: - * - *
    - *
  • Add arguments by supplying a long name and/or a short name. - * Arguments are validated using a regular expression. They can have - * a default value and a help string.
  • - *
  • Deprecated arguments.
  • - *
  • Custom regular expressions for argument validation.
  • - *
  • Set different argument name prefixes for native platform look and feel.
  • - *
  • QSettings support. Default values for arguments can be read from - * a QSettings object.
  • - *
  • Create a help text for the command line arguments with support for - * grouping arguments.
  • - *
- * - * Here is an example how to use this class inside a main function: - * - * \code - * #include - * #include - * #include - * - * int main(int argc, char** argv) - * { - * QCoreApplication app(argc, argv); - * // This is used by QSettings - * QCoreApplication::setOrganizationName("MyOrg"); - * QCoreApplication::setApplicationName("MyApp"); - * - * ctkCommandLineParser parser; - * // Use Unix-style argument names - * parser.setArgumentPrefix("--", "-"); - * // Enable QSettings support - * parser.enableSettings("disable-settings"); - * - * // Add command line argument names - * parser.addArgument("disable-settings", "", us::Any::Bool, "Do not use QSettings"); - * parser.addArgument("help", "h", us::Any::Bool, "Show this help text"); - * parser.addArgument("search-paths", "s", us::Any::StringList, "A list of paths to search"); - * - * // Parse the command line arguments - * bool ok = false; - * map parsedArgs = parser.parseArguments(QCoreApplication::arguments(), &ok); - * if (!ok) - * { - * QTextStream(stderr, QIODevice::WriteOnly) << "Error parsing arguments: " - * << parser.errorString() << "\n"; - * return EXIT_FAILURE; - * } - * - * // Show a help message - * if (parsedArgs.contains("help") || parsedArgs.contains("h")) - * { - * QTextStream(stdout, QIODevice::WriteOnly) << parser.helpText(); - * return EXIT_SUCCESS; - * } - * - * // Do something - * - * return EXIT_SUCCESS; - * } - * \endcode - */ - -using namespace std; - -class mitkCommandLineParser -{ - -public: - - enum Type { - String = 0, - Bool = 1, - StringList = 2, - Int = 3, - Float = 4, - InputDirectory = 5, - InputFile = 6, - OutputDirectory = 7, - OutputFile = 8, - InputImage = 9 - }; - - typedef std::vector< std::string > StringContainerType; - - /** - * Constructs a parser instance. - * - * If QSettings support is enabled by a call to enableSettings() - * a default constructed QSettings instance will be used when parsing - * the command line arguments. Make sure to call QCoreApplication::setOrganizationName() - * and QCoreApplication::setApplicationName() before using default - * constructed QSettings objects. - * - * @param newParent The QObject parent. - */ - mitkCommandLineParser(); - - ~mitkCommandLineParser(); - - /** - * Parse a given list of command line arguments. - * - * This method parses a list of string elements considering the known arguments - * added by calls to addArgument(). If any one of the argument - * values does not match the corresponding regular expression, - * ok is set to false and an empty map object is returned. - * - * The keys in the returned map object correspond to the long argument string, - * if it is not empty. Otherwise, the short argument string is used as key. The - * us::Any values can safely be converted to the type specified in the - * addArgument() method call. - * - * @param arguments A StringContainerType containing command line arguments. Usually - * given by QCoreApplication::arguments(). - * @param ok A pointer to a boolean variable. Will be set to true - * if all regular expressions matched, false otherwise. - * @return A map object mapping the long argument (if empty, the short one) - * to a us::Any containing the value. - */ - - map parseArguments(const StringContainerType &arguments, bool* ok = nullptr); - - /** - * Convenient method allowing to parse a given list of command line arguments. - * @see parseArguments(const StringContainerType &, bool*) - */ - map parseArguments(int argc, char** argv, bool* ok = nullptr); - - /** - * Returns a detailed error description if a call to parseArguments() - * failed. - * - * @return The error description, empty if no error occured. - * @see parseArguments(const StringContainerType&, bool*) - */ - string errorString() const; - - /** - * This method returns all unparsed arguments, i.e. all arguments - * for which no long or short name has been registered via a call - * to addArgument(). - * - * @see addArgument() - * - * @return A list containing unparsed arguments. - */ - const StringContainerType& unparsedArguments() const; - - /** - * Checks if the given argument has been added via a call - * to addArgument(). - * - * @see addArgument() - * - * @param argument The argument to be checked. - * @return true if the argument was added, false - * otherwise. - */ - bool argumentAdded(const string& argument) const; - - /** - * Checks if the given argument has been parsed successfully by a previous - * call to parseArguments(). - * - * @param argument The argument to be checked. - * @return true if the argument was parsed, false - * otherwise. - */ - bool argumentParsed(const string& argument) const; - - /** - * Adds a command line argument. An argument can have a long name - * (like --long-argument-name), a short name (like -l), or both. The type - * of the argument can be specified by using the type parameter. - * The following types are supported: - * - * - * - * - * - * - * - * - *
Type# of parametersDefault regular exprExample
us::Any::String1.*--test-string StringParameter
us::Any::Bool0does not apply--enable-something
us::Any::StringList-1.*--test-list string1 string2
us::Any::Int1-?[0-9]+--test-int -5
- * - * The regular expressions are used to validate the parameters of command line - * arguments. You can restrict the valid set of parameters by calling - * setExactMatchRegularExpression() for your argument. - * - * Optionally, a help string and a default value can be provided for the argument. If - * the us::Any type of the default value does not match type, an - * exception is thrown. Arguments with default values are always returned by - * parseArguments(). - * - * You can also declare an argument deprecated, by setting deprecated - * to true. Alternatively you can add a deprecated argument by calling - * addDeprecatedArgument(). - * - * If the long or short argument has already been added, or if both are empty strings, - * the method call has no effect. - * - * @param longarg The long argument name. - * @param shortarg The short argument name. - * @param type The argument type (see the list above for supported types). - * @param argLabel The label of this argument, when auto generated interface is used. - * @param argHelp A help string describing the argument. - * @param defaultValue A default value for the argument. - * @param ignoreRest All arguments after the current one will be ignored. - * @param deprecated Declares the argument deprecated. - * - * @see setExactMatchRegularExpression() - * @see addDeprecatedArgument() - * @throws std::logic_error If the us::Any type of defaultValue - * does not match type, a std::logic_error is thrown. - */ - void addArgument(const string& longarg, const string& shortarg, - Type type, const string& argLabel, const string& argHelp = string(), - const us::Any& defaultValue = us::Any(), bool optional=true, - bool ignoreRest = false, bool deprecated = false); - - /** - * Adds a deprecated command line argument. If a deprecated argument is provided - * on the command line, argHelp is displayed in the console and - * processing continues with the next argument. - * - * Deprecated arguments are grouped separately at the end of the help text - * returned by helpText(). - * - * @param longarg The long argument name. - * @param shortarg The short argument name. - * @param argHelp A help string describing alternatives to the deprecated argument. - */ - void addDeprecatedArgument(const string& longarg, const string& shortarg, const string& argLabel, - const string& argHelp); - - /** - * Sets a custom regular expression for validating argument parameters. The method - * errorString() can be used the get the last error description. - * - * @param argument The previously added long or short argument name. - * @param expression A regular expression which the arugment parameters must match. - * @param exactMatchFailedMessage An error message explaining why the parameter did - * not match. - * - * @return true if the argument was found and the regular expression was set, - * false otherwise. - * - * @see errorString() - */ - bool setExactMatchRegularExpression(const string& argument, const string& expression, - const string& exactMatchFailedMessage); - - /** - * The field width for the argument names without the help text. - * - * @return The argument names field width in the help text. - */ - int fieldWidth() const; - - /** - * Creates a help text containing properly formatted argument names and help strings - * provided by calls to addArgument(). The arguments can be grouped by - * using beginGroup() and endGroup(). - * - * @param charPad The padding character. - * @return The formatted help text. - */ - string helpText() const; - - /** - * Sets the argument prefix for long and short argument names. This can be used - * to create native command line arguments without changing the calls to - * addArgument(). For example on Unix-based systems, long argument - * names start with "--" and short names with "-", while on Windows argument names - * always start with "/". - * - * Note that all methods in ctkCommandLineParser which take an argument name - * expect the name as it was supplied to addArgument. - * - * Example usage: - * - * \code - * ctkCommandLineParser parser; - * parser.setArgumentPrefix("--", "-"); - * parser.addArgument("long-argument", "l", us::Any::String); - * StringContainerType args; - * args << "program name" << "--long-argument Hi"; - * parser.parseArguments(args); - * \endcode - * - * @param longPrefix The prefix for long argument names. - * @param shortPrefix The prefix for short argument names. - */ - void setArgumentPrefix(const string& longPrefix, const string& shortPrefix); - - /** - * Begins a new group for documenting arguments. All newly added arguments via - * addArgument() will be put in the new group. You can close the - * current group by calling endGroup() or be opening a new group. - * - * Note that groups cannot be nested and all arguments which do not belong to - * a group will be listed at the top of the text created by helpText(). - * - * @param description The description of the group - */ - void beginGroup(const string& description); - - /** - * Ends the current group. - * - * @see beginGroup(const string&) - */ - void endGroup(); - - /** - * Enables QSettings support in ctkCommandLineParser. If an argument name is found - * in the QSettings instance with a valid us::Any, the value is considered as - * a default value and overwrites default values registered with - * addArgument(). User supplied values on the command line overwrite - * values in the QSettings instance, except for arguments with multiple parameters - * which are merged with QSettings values. Call mergeSettings(false) - * to disable merging. - * - * See ctkCommandLineParser(QSettings*) for information about how to - * supply a QSettings instance. - * - * Additionally, a long and short argument name can be specified which will disable - * QSettings support if supplied on the command line. The argument name must be - * registered as a regular argument via addArgument(). - * - * @param disableLongArg Long argument name. - * @param disableShortArg Short argument name. - * - * @see ctkCommandLineParser(QSettings*) - */ - void enableSettings(const string& disableLongArg = "", - const string& disableShortArg = ""); - - /** - * Controlls the merging behavior of user values and QSettings values. - * - * If merging is on (the default), user supplied values for an argument - * which can take more than one parameter are merged with values stored - * in the QSettings instance. If merging is off, the user values overwrite - * the QSettings values. - * - * @param merge true enables QSettings merging, false - * disables it. - */ - void mergeSettings(bool merge); - - /** - * Can be used to check if QSettings support has been enabled by a call to - * enableSettings(). - * - * @return true if QSettings support is enabled, false - * otherwise. - */ - bool settingsEnabled() const; - - - /** - * Can be used to teach the parser to stop parsing the arguments and return False when - * an unknown argument is encountered. By default StrictMode is disabled. - * - * @see parseArguments(const StringContainerType &, bool*) - */ - void setStrictModeEnabled(bool strictMode); - - /** - * Is used to generate an XML output for any commandline program. - */ - void generateXmlOutput(); - - /** - * Is used to set the title of the auto generated interface. - * - * @param title The title of the app. - */ - void setTitle(std::string title); - /** - * Is used to set the contributor for the help view in the auto generated interface. - * - * @param contributor Contributor of the app. - */ - void setContributor(std::string contributor); - /** - * Is used to categorize the apps in the commandline module. - * - * @param category The category of the app. - */ - void setCategory(std::string category); - /** - * Is used as the help text in the auto generated interface. - * - * @param description A short description for the app. - */ - void setDescription(std::string description); - /** - * Is used to group several Parameters in one groupbox in the auto generated interface. - * Default name is "Parameters", with the tooltip: "Groupbox containing parameters." - * - * To change the group of several arguments, call this method before the arguments are added. - * - * @param name The name of the groupbox. - * @param tooltip The tooltip of the groupbox. - */ - void changeParameterGroup(std::string name, std::string tooltip); - -private: - class ctkInternal; - ctkInternal * Internal; - - string Title; - string Contributor; - string Category; - string Description; - string ParameterGroupName; - string ParameterGroupDescription; -}; - -#endif diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index e8c8e06df4..de59988c62 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,71 +1,72 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(mitk_modules Core + CommandLine AppUtil DCMTesting RDF LegacyIO DataTypesExt Overlays LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMTesting Qt4Qt5TestModule SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction ImageStatistics LegacyAdaptors SceneSerialization GraphAlgorithms Multilabel ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QmlItems QtWidgets QtWidgetsExt SegmentationUI DiffusionImaging GPGPU OpenIGTLink IGTBase IGT CameraCalibration RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport QtOverlays InputDevices ToFHardware ToFProcessing ToFUI US USUI DicomUI Simulation Remeshing Python Persistence OpenIGTLinkUI IGTUI VtkShaders DicomRT IOExt XNAT TubeGraph ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif()