source: src/UIElements/Dialog.hpp@ ff4fff9

CombiningParticlePotentialParsing
Last change on this file since ff4fff9 was 37a67f, checked in by Frederik Heber <heber@…>, 10 years ago

Replaced Query.. class and query..() function declarations in Dialog.. by boost preprocessor magic.

  • this removes a lot of copy&paste code.
  • Property mode set to 100644
File size: 11.5 KB
Line 
1/*
2 * Dialog.hpp
3 *
4 * Created on: Jan 5, 2010
5 * Author: crueger
6 */
7
8#ifndef DIALOG_HPP_
9#define DIALOG_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16
17#include<string>
18#include<list>
19#include<vector>
20
21#include <boost/filesystem.hpp>
22#include "LinearAlgebra/RealSpaceMatrix.hpp"
23#include "LinearAlgebra/Vector.hpp"
24#include "Parameters/Parameter.hpp"
25#include "Parameters/Specifics/KeyValuePair.hpp"
26
27class atom;
28class RealSpaceMatrix;
29class element;
30class molecule;
31
32/** Dialog is one of the two main classes of the UIFactory base class.
33 *
34 * The Dialog is meant for asking the user for information needed to perform
35 * actions he desires, such as asking for a position in space or a length.
36 *
37 * For this purpose there is the base class Query and numerous specializations
38 * for each of the types to be asked. There are primitives integer, doubles and
39 * string, but also advanced types such as element, molecule or Vector. There
40 * is also an empty query for displaying text.
41 *
42 * Note that the templatization of Dialog::query() allows for easy implementation
43 * of new types that correspond to/are derived from old ones.
44 *
45 * <H3>How do Dialogs operate?</H3>
46 *
47 * Dialogs are initiated by Action::FillDialog() function calls. Within Action::Call()
48 * a dialog is created and passed on to FillDialog(), which is specialized in each
49 * specific Action to ask for the specific parameter it needs.
50 *
51 * Dialogs are derived for each of the UI types
52 * -# CommandLineDialog
53 * -# QtDialog
54 * -# TextDialog
55 *
56 * This "asking" for parameters is done via the Query class. There are four types
57 * of Query types:
58 * -# Query, members in class Dialog
59 * -# CommandLineQuery, members in class CommandLineDialog
60 * -# QtQuery, members in class QtDialog
61 * -# TextQuery, members in class TextDialog
62 * Each embodies a certain way of asking the user for the specific type of parameter
63 * needed, e.g. a file via the TextMenu interface would be done in member functions of
64 * TextDialog::FileTextQuery.
65 *
66 *
67 * Generally, the sequence of events is as follows:
68 * -# Action::fillDialog() calls upon Dialog::query<T> for some type T, let's say T
69 * stands for double
70 * -# Dialog::query<double> call a function queryDouble()
71 * -# depending on the currently used UIFactory, the Dialog above is actually either
72 * of the three specialized types, let's say CommandLine. And we see that within
73 * CommandLineDialog we have the respective method ueryDouble() that registers
74 * a new instance of the class CommandLineDialog::DoubleCommandLineQuery.
75 * -# The Query's are first registered, as multiple parameters may be needed for
76 * a single Action and we don't want the popping up of a dialog window for each
77 * alone. Rather, we want to merge the Query's into a single Dialog. Therefore,
78 * they are first registered and then executed in sequence. This is done in
79 * Dialog::display(), i.e. when the dialog is finally shown to the user.
80 * -# Then each of the registered Query's, here our CommandLineDialog::
81 * DoubleCommandLineQuery, constructor is called.
82 * -# This will call the constructor of its base class, where the actual value
83 * is stored and later stored into the ValueStorage class by
84 * Dialog::Query::setResult().
85 * -# Also, e.g. for the Qt interface, the buttons, labels and so forth are
86 * created and added to the dialog.
87 * -# Now the users enters information for each UI something different happens:
88 * -# CommandLine: The actual value retrieval is done by the CommandLineParser and
89 * the boost::program_options library, the value is stored therein for the moment.
90 * (see here: http://www.boost.org/doc/libs/1_44_0/doc/html/program_options/)
91 * -# TextMenu: The value is requested via std::cin from the user.
92 * -# QtMenu: The users enters the value in a Dialog. Due to Qt necessities a
93 * Pipe class obtains the value from the Dialog with Qt's signal/slot mechanism
94 * and put it into Dialog::...Query value.
95 * -# in our case DoubleCommandLineQuery::handle() will be called. The value is
96 * retrieved and put into Dialog::DoubleQuery::tmp
97 * -# Finally, for each Query, also Dialog::DoubleQuery, setResult() is called which
98 * puts the value as a string into the ValueStorage under a given token that is
99 * associated with a type (and thereby we assure type-safety).
100 *
101 * <H3>Regarding derived types of types with already present queries</H3>
102 *
103 * Example: We have got a derived Vector class, called BoxVector, that is by any means
104 * a Vector but with one difference: it is always bound to lie within the current domain.
105 * With regards to type-casting it to and from a string however, nothing is different
106 * between Vector and BoxVector.
107 *
108 * So, do we need a new Query for this?
109 * No.
110 *
111 * We just have to do this:
112 * -# add a specialization of Dialog::query<BoxVector> where queryVector()is used.
113 * @code
114 * template <> void Dialog::query<BoxVector>(const std::string &title, const std::string &description) {
115 * queryVector(title, description);
116 * }
117 * @endcode
118 * -# make sure that
119 * -# ValueStorage::setCurrentValue() the specialization for class Vector has an
120 * if case also for BoxVector and does something appropriate.
121 * -# ValueStorage::queryCurrentValue() has another specialization doing the same
122 * as for Vector but for BoxVector in its signature.
123 *
124 * And that's all.
125 *
126 *
127 * <H3>Adding new queries</H3>
128 *
129 * Check first whether you really need a new query or whether we can derive it and re-use
130 * one of the present ones.
131 *
132 * Due to the three present UI interfaces we have to add a specific Query for each, here
133 * is a list:
134 * -# add a token (i.e. a unique name for the query parameter) and its type to the
135 * global list in \ref GlobalListOfParameterQueries.hpp. This will via boost
136 * preprocessor magic add definitions and some intermediatr template specializations.
137 * -# add a specialization for each of the UI interfaces of Dialog::...Query class.
138 * -# add class declaration of QtDialog::...Query in \ref QtQuery.hpp
139 * -# add CommandLineDialog::...Query, TextDialog::...Query, QtDialog::...Query
140 * -# TypeEnumContainer add new type to query. Make the Type name match with the token
141 * -# CommandLineParser::AddOptionToParser() add new type to query
142 * -# CommandLineParser_valdiates.[ch]pp: If given above as a new type
143 * program_options::value, define and implement a validate() function here.
144 *
145 * Note that the Empty..Query is always specificly present as it has not type and thus
146 * does not fit into the preprocessor magic scheme (on the plus side it also serves
147 * as a kind of visualization of what the preprocessor actually does).
148 *
149 */
150class Dialog
151{
152public:
153 Dialog(const std::string &_title);
154 virtual ~Dialog();
155
156 template <class T> void query(Parameter<T> &, const std::string ="", const std::string = "");
157
158 virtual void queryEmpty(const std::string ="", const std::string = "")=0;
159
160 /** With the following boost::preprocessor code we generate virtual function
161 * definitions for all desired query types in the abstract class Dialog.
162 */
163#include "UIElements/GlobalListOfParameterQueries.hpp"
164#include "UIElements/Dialog_impl_pre.hpp"
165
166 // iterate over all parameter query types
167 #if defined GLOBALLISTOFPARAMETERQUERIES_Token && defined GLOBALLISTOFPARAMETERQUERIES_Type
168 #define SUFFIX =0
169 #define BOOST_PP_LOCAL_MACRO(n) dialog_declaration(~, n, GLOBALLISTOFPARAMETERQUERIES_Token, GLOBALLISTOFPARAMETERQUERIES_Type)
170 #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMETERTOKENS-1)
171 #include BOOST_PP_LOCAL_ITERATE()
172 #undef dialog_declaration
173 #undef SUFFIX
174 #endif
175
176#include "Dialog_impl_undef.hpp"
177 /* End of preprocessor code piece */
178
179 virtual bool display();
180
181 virtual void handleAll();
182 virtual bool checkAll();
183 virtual void setAll();
184
185 virtual bool hasQueries();
186
187 virtual void update(){}
188
189public:
190 // methodology for handling queries
191 // all queries are stored and then performed at appropriate times
192
193 //these queries can be handled by this dialog
194
195 /** Base class for all queries.
196 *
197 * A query is request to the user for a value of a specific type.
198 * E.g. All \ref Action's need parameters to perform a specific function.
199 * These are obtained from the user at run-time via a Query regardless
200 * of the interface that the user is using.
201 *
202 * A Query just has title and description and serves as the general interface
203 * to queries. TQuery is a templatization of the Query containing a protected
204 * member variable of the specific type and also a Parameter<> reference of
205 * the type that actually belongs to the Action that triggered/created the
206 * Query. handle() is UI-specific and sets the (temporary) member variable.
207 * However, isValid() in TQuery checks via the Parameter<> reference whether
208 * the variable is valid with the given Validators and setResult() finally
209 * set the Parameter with the temporary variable.
210 *
211 * For each type there is a derived class per \b UI, e.g. for the
212 * \link userinterfaces-textmenu textmenu \endlink we have
213 * \ref BooleanTextQuery that derives from \ref TQuery<bool>. This derived
214 * class has to implement the Query::handle() function that actually sets
215 * the protected member variable to something the user has entered.
216 *
217 * Thanks to the templated TQuery this is a as simple as it can get. The
218 * handle() has to be UI-specific, hence has to be implemented once for
219 * every present UI. But all other code can be used for either of them.
220 *
221 * \section query-howto How to add another query?
222 *
223 * Let's say we want to query for a type called \a Value.
224 *
225 * Then, we do the following:
226 * -# add a virtual function queryValue inside class Dialog.
227 * -# now, for each of the GUIs we basically have to add a sub-class for the
228 * respective Query inside the derived Dialog that implements handle().
229 * -# QT: typically we use a onUpdate() function here attached the Qt
230 * signals and handle then just does nothing.
231 * -# CommandLine: nothing special, handle() imports value from \a
232 * CommandLineParser and sets the tmp variable.
233 * -# Text: nothing special, handle() queries the user and sets the tmp
234 * variable
235 */
236 class Query {
237 friend class Dialog;
238 public:
239 Query(const std::string _title, const std::string _description = "");
240 virtual ~Query();
241 virtual bool handle()=0;
242 virtual bool isValid()=0;
243 virtual void setResult()=0;
244 protected:
245 const std::string getTitle() const;
246 const std::string getDescription() const;
247 private:
248 const std::string title; //!< short title of the query
249 const std::string description; //!< longer description for tooltips or for help
250 };
251
252
253 template<class T>
254 class TQuery : public Query {
255 public:
256 TQuery(Parameter<T> &_param, const std::string title, const std::string _description = "") :
257 Query(title, _description), param(_param) {}
258 virtual ~TQuery(){}
259 virtual bool handle()=0;
260 virtual bool isValid(){ return param.isValid(temp); }
261 virtual void setResult(){ param.set(temp); }
262 protected:
263 T temp;
264 Parameter<T> &param;
265 };
266
267 // Empty Query is just meant for showing text, such as version, help, initial message or alike
268 class EmptyQuery : public Query {
269 public:
270 EmptyQuery(const std::string title, const std::string _description = "");
271 virtual ~EmptyQuery();
272 virtual bool handle()=0;
273 virtual bool isValid(){ return true; }
274 virtual void setResult();
275 };
276
277void registerQuery(Query* query);
278
279private:
280 std::list<Query*> queries;
281
282};
283
284#endif /* DIALOG_HPP_ */
Note: See TracBrowser for help on using the repository browser.