/* * Dialog.hpp * * Created on: Jan 5, 2010 * Author: crueger */ #ifndef DIALOG_HPP_ #define DIALOG_HPP_ #include #include #include #include #include "Box.hpp" #include "LinearAlgebra/Vector.hpp" class atom; class Box; class element; class molecule; /** Dialog is one of the two main classes of the UIFactory base class. * * The Dialog is meant for asking the user for information needed to perform * actions he desires, such as asking for a position in space or a length. * * For this purpose there is the base class Query and numerous specializations * for each of the types to be asked. There are primitives integer, doubles and * string, but also advanced types such as element, molecule or Vector. There * is also an empty query for displaying text. * * Note that the templatization of Dialog::query() allows for easy implementation * of new types that correspond to/are derived from old ones. * *

How do Dialogs operate?

* * Dialogs are initiated by Action::FillDialog() function calls. Within Action::Call() * a dialog is created and passed on to FillDialog(), which is specialized in each * specific Action to ask for the specific parameter it needs. * * Dialogs are derived for each of the UI types * -# CommandLineDialog * -# QtDialog * -# TextDialog * * This "asking" for parameters is done via the Query class. There are four types * of Query types: * -# Query, members in class Dialog * -# CommandLineQuery, members in class CommandLineDialog * -# QtQuery, members in class QtDialog * -# TextQuery, members in class TextDialog * Each embodies a certain way of asking the user for the specific type of parameter * needed, e.g. a file via the TextMenu interface would be done in member functions of * TextDialog::FileTextQuery. * * * Generally, the sequence of events is as follows: * -# Action::fillDialog() calls upon Dialog::query for some type T, let's say T * stands for double * -# Dialog::query call a function queryDouble() * -# depending on the currently used UIFactory, the Dialog above is actually either * of the three specialized types, let's say CommandLine. And we see that within * CommandLineDialog we have the respective method ueryDouble() that registers * a new instance of the class CommandLineDialog::DoubleCommandLineQuery. * -# The Query's are first registered, as multiple parameters may be needed for * a single Action and we don't want the popping up of a dialog window for each * alone. Rather, we want to merge the Query's into a single Dialog. Therefore, * they are first registered and then executed in sequence. This is done in * Dialog::display(), i.e. when the dialog is finally shown to the user. * -# Then each of the registered Query's, here our CommandLineDialog:: * DoubleCommandLineQuery, constructor is called. * -# This will call the constructor of its base class, where the actual value * is stored and later stored into the ValueStorage class by * Dialog::Query::setResult(). * -# Also, e.g. for the Qt interface, the buttons, labels and so forth are * created and added to the dialog. * -# Now the users enters information for each UI something different happens: * -# CommandLine: The actual value retrieval is done by the CommandLineParser and * the boost::program_options library, the value is stored therein for the moment. * (see here: http://www.boost.org/doc/libs/1_44_0/doc/html/program_options/) * -# TextMenu: The value is requested via std::cin from the user. * -# QtMenu: The users enters the value in a Dialog. Due to Qt necessities a * Pipe class obtains the value from the Dialog with Qt's signal/slot mechanism * and put it into Dialog::...Query value. * -# in our case DoubleCommandLineQuery::handle() will be called. The value is * retrieved and put into Dialog::DoubleQuery::tmp * -# Finally, for each Query, also Dialog::DoubleQuery, setResult() is called which * puts the value as a string into the ValueStorage under a given token that is * associated with a type (and thereby we assure type-safety). * *

Regarding derived types of types with already present queries

* * Example: We have got a derived Vector class, called BoxVector, that is by any means * a Vector but with one difference: it is always bound to lie within the current domain. * With regards to type-casting it to and from a string however, nothing is different * between Vector and BoxVector. * * So, do we need a new Query for this? * No. * * We just have to do this: * -# add a specialization of Dialog::query where queryVector()is used. * @code * template <> void Dialog::query(const char *token, std::string description) { * queryVector(token, false, description); * } * @endcode * -# make sure that * -# ValueStorage::setCurrentValue() the specialization for class Vector has an * if case also for BoxVector and does something appropriate. * -# ValueStorage::queryCurrentValue() has another specialization doing the same * as for Vector but for BoxVector in its signature. * * And that's all. * * *

Adding new queries

* * Check first whether you really need a new query or whether we can derive it and re-use * one of the present ones. * * Due to the three present UI interfaces we have to add a specific Query for each, here * is a list: * -# add ValueStorage::setCurrentValue() and ValueStorage::queryCurrentValue() for * both types * -# add Dialog::query...() * -# add Dialog::query<>() specialization calling the above function * -# add CommandLineDialog::query...(), TextDialog::query...(), and QtDialog::query...(), * i.e. for each of the three interface * -# add Dialog::...Query class with tmp value of desired type * -# add CommandLineDialog::...Query, TextDialog::...Query, QtDialog::...Query * -# you probably also need a QtDialog::...QueryPipe() to handle the signal/slot stuff, * Qt's moc does not like nested classes. Hence, this has to go extra. * */ class Dialog { public: Dialog(); virtual ~Dialog(); template void query(const char *, std::string = ""); virtual void queryEmpty(const char *, std::string = "")=0; virtual void queryBoolean(const char *, std::string = "")=0; virtual void queryInt(const char *, std::string = "")=0; virtual void queryInts(const char *, std::string = "")=0; virtual void queryDouble(const char*, std::string = "")=0; virtual void queryDoubles(const char*, std::string = "")=0; virtual void queryString(const char*, std::string = "")=0; virtual void queryStrings(const char*, std::string = "")=0; virtual void queryAtom(const char*,std::string = "")=0; virtual void queryAtoms(const char*,std::string = "")=0; virtual void queryMolecule(const char*, std::string = "")=0; virtual void queryMolecules(const char*, std::string = "")=0; virtual void queryVector(const char*,bool, std::string = "")=0; virtual void queryVectors(const char*,bool, std::string = "")=0; virtual void queryBox(const char*, std::string = "")=0; virtual void queryElement(const char*, std::string = "")=0; virtual void queryElements(const char*, std::string = "")=0; virtual void queryFile(const char*, std::string = "")=0; virtual bool display(); virtual bool checkAll(); virtual void setAll(); virtual bool hasQueries(); protected: // methodology for handling queries // all queries are stored and then performed at appropriate times //these queries can be handled by this dialog //TODO: Find a way to reduce complexity... //needs O(N*M) query classes, where N is the number of query types and M is the number of GUIs //usual approach for reducing inheritance complexity (strategy pattern) does not work, //due to lack of common code for query types as well as GUI-Types (all subtypes differ a lot) /** Base class for all queries. * * *

How to add another query?

* * Let's say we want to query for a type called \a Value. * * Then, we do the following: * -# Add a class ValueQuery inside class Dialog, the class contains * -# constructor/destructor (latter virtual! because of derived class) * -# virtual bool handle() and virtual void setResult() * -# a protected member tmp of type Value (NOTE: herein the result is stored) * -# if temporaries for conversion are needed put them in here * -# add a function queryValue * -# now, for each of the GUIs we basically have to repeat the above, i.e. * add the class and the function that implement the virtual ones above. * -# QT: an extra class called ValueQtQueryPipe that actually handles * showing dialogs to obtain the value and placing it into the \a tmp * variable (via a given pointer to it as reference). handle() will * simply return true. This is needed because of a restriction of Qt4: * its meta-object-compiler does not like nested classes. * -# CommandLine: nothing special, handle() imports value from \a * CommandLineParser and sets the tmp variable. * -# Text: nothing special, handle() queries the user and sets the tmp * variable */ class Query { friend class Dialog; public: Query(std::string _title, std::string _description = ""); virtual ~Query(); virtual bool handle()=0; virtual void setResult()=0; protected: const std::string getTitle() const; const std::string getDescription() const; private: std::string title; //!< short title of the query std::string description; //!< longer description for tooltips or for help }; // Empty Query is just meant for showing text, such as version, help, initial message or alike class EmptyQuery : public Query { public: EmptyQuery(std::string title, std::string _description = ""); virtual ~EmptyQuery(); virtual bool handle()=0; virtual void setResult(); }; //Specialized classes for certain types. GUI-Types are not specialized at this time class BooleanQuery : public Query { public: BooleanQuery(std::string title, std::string _description = ""); virtual ~BooleanQuery(); virtual bool handle()=0; virtual void setResult(); protected: bool tmp; }; class IntQuery : public Query { public: IntQuery(std::string title, std::string _description = ""); virtual ~IntQuery(); virtual bool handle()=0; virtual void setResult(); protected: int tmp; }; class IntsQuery : public Query { public: IntsQuery(std::string title, std::string _description = ""); virtual ~IntsQuery(); virtual bool handle()=0; virtual void setResult(); protected: int temp; std::vector tmp; }; class DoubleQuery : public Query { public: DoubleQuery(std::string title, std::string _description = ""); virtual ~DoubleQuery(); virtual bool handle()=0; virtual void setResult(); protected: double tmp; }; class DoublesQuery : public Query { public: DoublesQuery(std::string title, std::string _description = ""); virtual ~DoublesQuery(); virtual bool handle()=0; virtual void setResult(); protected: double temp; std::vector tmp; }; class StringQuery : public Query { public: StringQuery(std::string title, std::string _description = ""); virtual ~StringQuery(); virtual bool handle()=0; virtual void setResult(); protected: std::string tmp; }; class StringsQuery : public Query { public: StringsQuery(std::string title, std::string _description = ""); virtual ~StringsQuery(); virtual bool handle()=0; virtual void setResult(); protected: std::string temp; std::vector tmp; }; class MoleculeQuery : public Query { public: MoleculeQuery(std::string title, std::string _description = ""); virtual ~MoleculeQuery(); virtual bool handle()=0; virtual void setResult(); protected: const molecule *tmp; }; class MoleculesQuery : public Query { public: MoleculesQuery(std::string title, std::string _description = ""); virtual ~MoleculesQuery(); virtual bool handle()=0; virtual void setResult(); protected: const molecule * temp; std::vector tmp; }; class AtomQuery : public Query { public: AtomQuery(std::string title, std::string _description = ""); virtual ~AtomQuery(); virtual bool handle()=0; virtual void setResult(); protected: const atom *tmp; }; class AtomsQuery : public Query { public: AtomsQuery(std::string title, std::string _description = ""); virtual ~AtomsQuery(); virtual bool handle()=0; virtual void setResult(); protected: const atom *temp; std::vector tmp; }; class VectorQuery : public Query { public: VectorQuery(std::string title,bool _check, std::string _description = ""); virtual ~VectorQuery(); virtual bool handle()=0; virtual void setResult(); protected: Vector tmp; bool check; }; class VectorsQuery : public Query { public: VectorsQuery(std::string title,bool _check, std::string _description = ""); virtual ~VectorsQuery(); virtual bool handle()=0; virtual void setResult(); protected: Vector temp; std::vector tmp; bool check; }; class BoxQuery : public Query { public: BoxQuery(std::string title, std::string _description = ""); virtual ~BoxQuery(); virtual bool handle()=0; virtual void setResult(); protected: Box tmp; }; class ElementQuery : public Query { public: ElementQuery(std::string title, std::string _description = ""); virtual ~ElementQuery(); virtual bool handle()=0; virtual void setResult(); protected: const element * tmp; }; class ElementsQuery : public Query { public: ElementsQuery(std::string title, std::string _description = ""); virtual ~ElementsQuery(); virtual bool handle()=0; virtual void setResult(); protected: const element *temp; std::vector tmp; }; class FileQuery : public Query { public: FileQuery(std::string title, std::string _description = ""); virtual ~FileQuery(); virtual bool handle()=0; virtual void setResult(); protected: boost::filesystem::path tmp; }; void registerQuery(Query* query); private: std::list queries; }; #endif /* DIALOG_HPP_ */