diff --git a/Modules/Forms/include/mitkQuestion.h b/Modules/Forms/include/mitkQuestion.h index 83a18f9d30..56829ecb5a 100644 --- a/Modules/Forms/include/mitkQuestion.h +++ b/Modules/Forms/include/mitkQuestion.h @@ -1,58 +1,238 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkQuestion_h #define mitkQuestion_h #include #include #include #include namespace mitk::Forms { + /** \brief Abstract base class for all types of questions used in a Form. + * + * Please make sure to read the full documentation of the pure virtual functions in particular to + * fully understand implications and requirements. + */ class MITKFORMS_EXPORT Question { public: Question(); virtual ~Question(); + /** \brief Get the literal question. + */ std::string GetQuestionText() const; + + /** \brief Set the literal question. + */ void SetQuestionText(const std::string& question); + /** \brief Check whether a response to this question is required to complete a form. + */ + bool IsRequired() const; + + /** \brief Set whether a resonse to this question is required to complete a form. + * + * A question is not required by default. + */ + void SetRequired(bool required = true); + + /** \brief Get the text that should be displayed to clearly mark a question as required. + * + * This text is typically displayed as soon as a response to a required question is missing. + * The method can be overridden to customize the default text, e.g. for more complex types + * of questions, where specific guidance is beneficial. + * + * \sa IsComplete() + */ + virtual std::string GetRequiredText() const; + + /** \name Pure virtual functions + * + * Question is an abstract base class. Derive from this class to add a new type of question + * and override the following pure virtual functions. Please read the full documentation for + * all of these functions to fully understand implications and requirements. + * + * Do not forget to register any new type of question by calling IQuestionFactory::Register() + * like it is done in this module's activator class. + * + * \sa IQuestionFactory + * \{ + */ + + /** \brief Return the type of a question as string, e.g. "Multiple choice" or "Drop-down". + * + * This method is essential for the deserialization of questions into their correct type, resp. + * derived class. The type string is used by IQuestionFactory to look up a registered prototype + * instance of a certain type to create another instance of it. + * + * The type string does not have to match the class name or follow any other convention except + * for it must be unique amongst all question types. Prefer natural language like in the + * examples above in case it is used in a user interface to display a question's type. + * + * \code{.cpp} + * std::string RhetoricalQuestion::GetType() const + * { + * return "Rhetorical"; + * } + * \endcode + * + * \sa CreateAnother() + */ virtual std::string GetType() const = 0; - virtual Question* CreateAnother() const = 0; - virtual void FromJSON(const nlohmann::ordered_json& j) = 0; - virtual void ToJSON(nlohmann::ordered_json& j) const = 0; + /** \brief Create a new instance of the derived question class type. + * + * This method is mainly used by IQuestionFactory to create new instances from registered + * prototype instances based on a type string. + * + * \code{.cpp} + * Question* RhetoricalQuestion::CreateAnother() const + * { + * return new RhetoricalQuestion; + * } + * \endcode + * + * \sa GetType() + */ + virtual Question* CreateAnother() const = 0; + /** \brief Return the question's response(s) as strings. + * + * This is the single common generic interface for retrieving responses from all types + * of questions. It is typically used to store responses in text-based formats like CSV. + * + * It is implemented as vector since certain types of questions like a checkboxes question + * may support multiple responses. Otherwise, return a vector with a single element. + * + * \code{.cpp} + * std::vector RhetoricalQuestion::GetResponsesAsStrings() const + * { + * return { m_Response }; + * } + * \endcode + */ virtual std::vector GetResponsesAsStrings() const = 0; + + /** \brief Clear the/all response(s). + */ virtual void ClearResponses() = 0; - virtual std::string GetRequiredText() const; + /** \brief Check if a question is considered to be answered completely. + * + * This method is typically called when IsRequired() returns \c true to determine + * whether the requirements are fulfilled. + */ virtual bool IsComplete() const = 0; - void SetRequired(bool required = true); - bool IsRequired() const; + /** \brief Deserialize from JSON. + * + * Polymorphism and the use of base class pointers make it necessary to implement serialization + * through member functions. Using the pure native approach of the "JSON for Modern C++" library + * via free functions would lead to partially serialized instances of derived classes. + * + * The actual implementation can and should still be located in a corresponding %from_json() + * free function but we also need the indirection through this member function. + * + * \code{.cpp} + * void RhetoricalQuestion::FromJSON(const nlohmann::ordered_json& j) + * { + * from_json(j, *this); + * } + * \endcode + * + * \sa from_json(const nlohmann::ordered_json& j, Question& q) + */ + virtual void FromJSON(const nlohmann::ordered_json& j) = 0; + + /** \brief Serialize to JSON. + * + * Polymorphism and the use of base class pointers make it necessary to implement serialization + * through member functions. Using the pure native approach of the "JSON for Modern C++" library + * via free functions would lead to partially serialized instances of derived classes. + * + * The actual implementation can and should still be located in a corresponding %to_json() free + * function but we also need the indirection through this member function. + * + * \code{.cpp} + * void RhetoricalQuestion::ToJSON(nlohmann::ordered_json& j) const + * { + * to_json(j, *this); + * } + * \endcode + * + * \sa to_json(nlohmann::ordered_json& j, const Question& q) + */ + virtual void ToJSON(nlohmann::ordered_json& j) const = 0; + + /**\}*/ private: std::string m_QuestionText; bool m_IsRequired; }; + /** \brief Deserialize from JSON. + * + * Polymorphism and the use of base class pointers make it necessary to implement serialization + * through member functions. Using the pure native approach of the "JSON for Modern C++" library + * via free functions would lead to partially serialized instances of derived classes. + * + * The actual implementation can and should still be located in a %from_json() free function but we + * also need the indirection through a corresponding member function. + * + * Overloaded functions for derived Question classes should reuse their base class versions of + * the function. + * + * \code{.cpp} + * void mitk::Forms::from_json(const ordered_json& j, RhetoricalQuestion& q) + * { + * from_json(j, static_cast(q)); + * // TODO: Deserialization of members exclusive to the derived class... + * } + * \endcode + * + * \sa Question::FromJSON() + */ MITKFORMS_EXPORT void from_json(const nlohmann::ordered_json& j, Question& q); + + /** \brief Serialize to JSON. + * + * Polymorphism and the use of base class pointers make it necessary to implement serialization + * through member functions. Using the pure native approach of the "JSON for Modern C++" library + * via free functions would lead to partially serialized instances of derived classes. + * + * The actual implementation can and should still be located in a %to_json() free function but we + * also need the indirection through a corresponding member function. + * + * Overloaded functions for derived Question classes should reuse their base class versions of + * the function. + * + * \code{.cpp} + * void mitk::Forms::to_json(nlohmann::ordered_json& j, const RhetoricalQuestion& q) + * { + * to_json(j, static_cast(q)); + * // TODO: Serialization of members exclusive to the derived class... + * } + * \endcode + * + * \sa Question::ToJSON() + */ MITKFORMS_EXPORT void to_json(nlohmann::ordered_json& j, const Question& q); } #endif