source: src/UIElements/Dialog.hpp

Candidate_v1.6.1
Last change on this file was f4b6bc9, checked in by Frederik Heber <frederik.heber@…>, 7 years ago

Query::handle() no longer returns bool but has internal result flag.

  • we use this flag conditionally in setResult(), i.e. if the handle() has failed, then we should not set its result which might overwrite a present default value in the parameter.
  • this fixes the problem with StepWorldTime which has a default value of 1 but which was overwritten with 0 because of the non-conditionally calling of setResult().
  • this required change of "output-types" default parameter to an empty vector. So far, we were just lucky that this actually worked.
  • also StoreSaturatedFragmentAction needed the same change as default values have to be consistent over the specific token.
  • Property mode set to 100644
File size: 13.4 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 virtual void queryVector(Parameter<Vector> &, const std::string ="", const std::string = "")=0;
161 virtual void queryVectors(Parameter< std::vector<Vector> > &, const std::string ="", const std::string = "")=0;
162
163 /** With the following boost::preprocessor code we generate virtual function
164 * definitions for all desired query types in the abstract class Dialog.
165 */
166#include "UIElements/GlobalListOfParameterQueries.hpp"
167#include "UIElements/Dialog_impl_pre.hpp"
168
169 // iterate over all parameter query types
170 #if defined GLOBALLISTOFPARAMETERQUERIES_Token && defined GLOBALLISTOFPARAMETERQUERIES_Type
171 #define SUFFIX =0
172 #define BOOST_PP_LOCAL_MACRO(n) dialog_declaration(~, n, GLOBALLISTOFPARAMETERQUERIES_Token, GLOBALLISTOFPARAMETERQUERIES_Type)
173 #define BOOST_PP_LOCAL_LIMITS (0, MAXPARAMETERTOKENS-1)
174 #include BOOST_PP_LOCAL_ITERATE()
175 #undef dialog_declaration
176 #undef SUFFIX
177 #endif
178
179#include "Dialog_impl_undef.hpp"
180 /* End of preprocessor code piece */
181
182 virtual bool display();
183
184 virtual void handleAll();
185 virtual bool checkAll();
186 virtual void setAll();
187
188 virtual bool hasQueries();
189
190 virtual void update(){}
191
192public:
193 // methodology for handling queries
194 // all queries are stored and then performed at appropriate times
195
196 //these queries can be handled by this dialog
197
198 /** Base class for all queries.
199 *
200 * A query is request to the user for a value of a specific type.
201 * E.g. All \ref Action's need parameters to perform a specific function.
202 * These are obtained from the user at run-time via a Query regardless
203 * of the interface that the user is using.
204 *
205 * A Query just has title and description and serves as the general interface
206 * to queries. TQuery is a templatization of the Query containing a protected
207 * member variable of the specific type and also a Parameter<> reference of
208 * the type that actually belongs to the Action that triggered/created the
209 * Query. handle() is UI-specific and sets the (temporary) member variable.
210 * However, isValid() in TQuery checks via the Parameter<> reference whether
211 * the variable is valid with the given Validators and setResult() finally
212 * set the Parameter with the temporary variable.
213 *
214 * For each type there is a derived class per \b UI, e.g. for the
215 * \link userinterfaces-textmenu textmenu \endlink we have
216 * \ref BooleanTextQuery that derives from \ref TQuery<bool>. This derived
217 * class has to implement the Query::handle() function that actually sets
218 * the protected member variable to something the user has entered.
219 *
220 * Thanks to the templated TQuery this is a as simple as it can get. The
221 * handle() has to be UI-specific, hence has to be implemented once for
222 * every present UI. But all other code can be used for either of them.
223 *
224 * \section query-howto How to add another query?
225 *
226 * Let's say we want to query for a type called \a Value.
227 *
228 * Then, we do the following:
229 * -# add a virtual function queryValue inside class Dialog.
230 * -# now, for each of the GUIs we basically have to add a sub-class for the
231 * respective Query inside the derived Dialog that implements handle().
232 * -# QT: typically we use a onUpdate() function here attached the Qt
233 * signals and handle then just does nothing.
234 * -# CommandLine: nothing special, handle() imports value from \a
235 * CommandLineParser and sets the tmp variable.
236 * -# Text: nothing special, handle() queries the user and sets the tmp
237 * variable
238 */
239 class Query {
240 friend class Dialog;
241 public:
242 Query(const std::string _title, const std::string _description = "");
243 virtual ~Query();
244 virtual void handle()=0;
245 virtual bool isValid()=0;
246 virtual void setResult()=0;
247 protected:
248 const std::string getTitle() const;
249 const std::string getDescription() const;
250 private:
251 const std::string title; //!< short title of the query
252 const std::string description; //!< longer description for tooltips or for help
253 };
254
255 template<class T>
256 class TQuery : public Query {
257 public:
258 TQuery(Parameter<T> &_param, const std::string title, const std::string _description = "") :
259 Query(title, _description), handleSuccess(false), param(_param) {}
260 virtual ~TQuery(){}
261 virtual void handle()=0;
262 virtual bool isValid(){ return param.isValid(temp); }
263 virtual void setResult(){ if (handleSuccess) param.set(temp); }
264 protected:
265 T temp;
266 bool handleSuccess;
267 Parameter<T> &param;
268 };
269
270 // Empty Query is just meant for showing text, such as version, help, initial message or alike
271 class EmptyQuery : public Query {
272 public:
273 EmptyQuery(const std::string title, const std::string _description = "");
274 virtual ~EmptyQuery();
275 virtual void handle()=0;
276 virtual bool isValid(){ return true; }
277 virtual void setResult();
278 };
279
280void registerQuery(Query* query);
281
282private:
283 std::list<Query*> queries;
284
285};
286
287// we have specialization of Vector to allow internal storing as string
288template <>
289void Dialog::query<Vector>(Parameter<Vector> &, const std::string, const std::string);
290template <>
291void Dialog::query< std::vector<Vector> >(Parameter< std::vector<Vector> > &, const std::string, const std::string);
292
293/** Template specialization for Query<Vector> to allow internal storing of a
294 * string instead of a Vector.
295 *
296 * Because we need to evaluate the string as a possible GeometryRegistry key
297 * and we may do this only when the Action (whose options we are querying)
298 * is executed, not before.
299 */
300template <>
301class Dialog::TQuery<Vector> : public Query {
302public:
303 TQuery(Parameter<Vector> &_param, const std::string title, const std::string _description = "") :
304 Query(title, _description), handleSuccess(false), param(_param) {}
305 virtual ~TQuery(){}
306 virtual void handle()=0;
307 virtual bool isValid(){ return param.isValidAsString(temp); }
308 virtual void setResult(){ if (handleSuccess) param.setAsString(temp); }
309protected:
310 std::string temp;
311 bool handleSuccess;
312 Parameter<Vector> &param;
313};
314
315template <>
316class Dialog::TQuery< std::vector<Vector> > : public Query {
317public:
318 TQuery(Parameter< std::vector<Vector> > &_param, const std::string title, const std::string _description = "") :
319 Query(title, _description), handleSuccess(false), param(_param) {}
320 virtual ~TQuery(){}
321 virtual void handle()=0;
322 virtual bool isValid();
323 virtual void setResult();
324protected:
325 std::vector<std::string> temp;
326 bool handleSuccess;
327 Parameter< std::vector<Vector> > &param;
328};
329
330
331#endif /* DIALOG_HPP_ */
Note: See TracBrowser for help on using the repository browser.