The Battle for Wesnoth  1.15.12+dev
policy_order.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2018 by Mark de Wever <koraq@xs4all.nl>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #pragma once
16 
19 #include "gui/core/log.hpp"
20 #include "gui/widgets/widget.hpp"
21 
22 #include <iostream>
23 #include <cassert>
24 
25 namespace gui2
26 {
27 
28 namespace iteration
29 {
30 
31 namespace policy
32 {
33 
34 namespace order
35 {
36 
37 template <bool VW, bool VG, bool VC>
38 class bottom_up : public visit_level<VW, walker_base::self>,
39  public visit_level<VG, walker_base::internal>,
40  public visit_level<VC, walker_base::child>
41 {
45 
46 public:
47  explicit bottom_up(widget& root) : root_(root.create_walker()), stack_()
48  {
49  TST_GUI_I << "Constructor: ";
50  while(!visit_child::at_end(*root_)) {
51  stack_.push_back(root_);
52  root_ = visit_child::get(*root_)->create_walker();
53  TST_GUI_I << " Down widget '" << operator*().id() << "'.";
54  }
55 
56  if(!at_end()) {
57  TST_GUI_I << " Finished at '" << operator*().id() << "'.\n";
58  } else {
59  TST_GUI_I << " Finished at the end.\n";
60  }
61  }
62 
64  {
65  delete root_;
67  itor != stack_.end();
68  ++itor) {
69 
70  delete *itor;
71  }
72  }
73 
74  bool at_end() const
75  {
76  return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
77  && visit_child::at_end(*root_);
78  }
79 
80  bool next()
81  {
82  if(at_end()) {
83  ERR_GUI_I << "Tried to move beyond end of the iteration range."
84  << std::endl;
85  throw range_error("Tried to move beyond end of range.");
86  }
87 
88  TST_GUI_I << "At '" << operator*().id() << "'.";
89 
90  /***** WIDGET *****/
91  TST_GUI_I << " Iterate widget:";
92  if(!visit_widget::at_end(*root_)) {
93  switch(visit_widget::next(*root_)) {
94  case walker_base::valid:
95  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
96  return true;
98  TST_GUI_I << " reached the end.";
99  break;
100  case walker_base::fail:
101  TST_GUI_I << "\n";
102  ERR_GUI_E << "Tried to move beyond end of "
103  "the widget iteration range.\n";
104  throw range_error("Tried to move beyond end of range.");
105  }
106  } else {
107  TST_GUI_I << " failed.";
108  }
109 
110  /***** GRID *****/
111  TST_GUI_I << " Iterate grid:";
112  if(!visit_grid::at_end(*root_)) {
113  switch(visit_grid::next(*root_)) {
114  case walker_base::valid:
115  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
116  return true;
118  TST_GUI_I << " reached the end.";
119  break;
120  case walker_base::fail:
121  TST_GUI_I << "\n";
122  ERR_GUI_E << "Tried to move beyond end of "
123  "the grid iteration range.\n";
124  throw range_error("Tried to move beyond end of range.");
125  }
126  } else {
127  TST_GUI_I << " failed.";
128  }
129 
130  /***** TRAVERSE CHILDREN *****/
131 
132  TST_GUI_I << " Iterate child:";
133  if(visit_child::at_end(*root_)) {
134  if(stack_.empty()) {
135  TST_GUI_I << " Finished iteration.\n";
136  return false;
137  } else {
138  delete root_;
139 
140  root_ = stack_.back();
141  stack_.pop_back();
142  TST_GUI_I << " Up '" << operator*().id() << "'.";
143  }
144  }
145  TST_GUI_I << " Iterate child:";
146  if(!visit_child::at_end(*root_)) {
147  switch(visit_child::next(*root_)) {
148  case walker_base::valid:
149  TST_GUI_I << " visit '" << operator*().id() << "'.";
150  break;
152  TST_GUI_I << " reached the end.";
153  break;
154  case walker_base::fail:
155  TST_GUI_I << "\n";
156  ERR_GUI_E << "Tried to move beyond end of "
157  "the child iteration range.\n";
158  throw range_error("Tried to move beyond end of range.");
159  }
160  } else {
161  TST_GUI_I << " already at the end.";
162  }
163 
164  while(!visit_child::at_end(*root_)) {
165  stack_.push_back(root_);
166  root_ = visit_child::get(*root_)->create_walker();
167  TST_GUI_I << " Down widget '" << operator*().id() << "'.";
168  }
169  TST_GUI_I << " Visit '" << operator*().id() << "'.\n";
170  return true;
171  }
172 
174  {
175  if(at_end()) {
176  ERR_GUI_I << "Tried to defer beyond end its "
177  "iteration range iterator.\n";
178  throw logic_error("Tried to defer an invalid iterator.");
179  }
180  if(!visit_widget::at_end(*root_)) {
181  return *visit_widget::get(*root_);
182  }
183  if(!visit_grid::at_end(*root_)) {
184  return *visit_grid::get(*root_);
185  }
186  if(!visit_child::at_end(*root_)) {
187  return *visit_child::get(*root_);
188  }
189  ERR_GUI_I << "The iterator ended in an unknown "
190  "state while deferring itself.\n";
191  throw logic_error("Tried to defer an invalid iterator.");
192  }
193 
194 private:
196 
197  std::vector<iteration::walker_base*> stack_;
198 };
199 
200 template <bool VW, bool VG, bool VC>
201 class top_down : public visit_level<VW, walker_base::self>,
202  public visit_level<VG, walker_base::internal>,
203  public visit_level<VC, walker_base::child>
204 {
208 
209 public:
210  explicit top_down(widget& root) : root_(root.create_walker()), stack_()
211  {
212  }
213 
215  {
216  delete root_;
218  itor != stack_.end();
219  ++itor) {
220 
221  delete *itor;
222  }
223  }
224 
225  bool at_end() const
226  {
227  return visit_widget::at_end(*root_) && visit_grid::at_end(*root_)
228  && visit_child::at_end(*root_);
229  }
230 
231  bool next()
232  {
233  if(at_end()) {
234  ERR_GUI_I << "Tried to move beyond end of the iteration range."
235  << std::endl;
236  throw range_error("Tried to move beyond end of range.");
237  }
238 
239  TST_GUI_I << "At '" << operator*().id() << "'.";
240 
241  /***** WIDGET *****/
242  TST_GUI_I << " Iterate widget:";
243  if(!visit_widget::at_end(*root_)) {
244  switch(visit_widget::next(*root_)) {
245  case walker_base::valid:
246  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
247  return true;
249  TST_GUI_I << " reached the end.";
250  break;
251  case walker_base::fail:
252  TST_GUI_I << "\n";
253  ERR_GUI_E << "Tried to move beyond end of the "
254  "widget iteration range.\n";
255  throw range_error("Tried to move beyond end of range.");
256  }
257  } else {
258  TST_GUI_I << " failed.";
259  }
260 
261  /***** GRID *****/
262  TST_GUI_I << " Iterate grid:";
263  if(!visit_grid::at_end(*root_)) {
264  switch(visit_grid::next(*root_)) {
265  case walker_base::valid:
266  TST_GUI_I << " visit '" << operator*().id() << "'.\n";
267  return true;
269  TST_GUI_I << " reached the end.";
270  break;
271  case walker_base::fail:
272  TST_GUI_I << "\n";
273  ERR_GUI_E << "Tried to move beyond end of the grid "
274  "iteration range.\n";
275  throw range_error("Tried to move beyond end of range.");
276  }
277  } else {
278  TST_GUI_I << " failed.";
279  }
280 
281  /***** TRAVERSE CHILDREN *****/
282 
283  TST_GUI_I << " Iterate child:";
284  if(visit_child::at_end(*root_)) {
285  TST_GUI_I << " reached the end.";
286  up();
287  } else {
288  TST_GUI_I << " proceed.";
289  }
290 
291  if(!visit_child::at_end(*root_)) {
292  stack_.push_back(root_);
293  root_ = visit_child::get(*root_)->create_walker();
294 
295  assert(root_);
296  assert(!at_end());
297  TST_GUI_I << " Down and visit '" << operator*().id() << "'.\n";
298  return true;
299  }
300 
301  TST_GUI_I << " Finished iteration.\n";
302  return false;
303  }
304 
306  {
307  if(at_end()) {
308  ERR_GUI_I << "Tried to defer beyond end of the iteration "
309  "range iterator.\n";
310  throw logic_error("Tried to defer an invalid iterator.");
311  }
312  if(!visit_widget::at_end(*root_)) {
313  return *visit_widget::get(*root_);
314  }
315  if(!visit_grid::at_end(*root_)) {
316  return *visit_grid::get(*root_);
317  }
318  if(!visit_child::at_end(*root_)) {
319  return *visit_child::get(*root_);
320  }
321  ERR_GUI_I << "The iterator ended in an unknown "
322  "state while deferring iteself.\n";
323  throw logic_error("Tried to defer an invalid iterator.");
324  }
325 
326 private:
327  bool up()
328  {
329  while(!stack_.empty()) {
330  delete root_;
331 
332  root_ = stack_.back();
333  stack_.pop_back();
334  TST_GUI_I << " Up widget '" << operator*().id() << "'. Iterate:";
335  switch(visit_child::next(*root_)) {
336  case walker_base::valid:
337  TST_GUI_I << " reached '" << operator*().id() << "'.";
338  return true;
340  TST_GUI_I << " failed.";
341  break;
342  case walker_base::fail:
343  throw range_error("Tried to move beyond end of range.");
344  }
345  }
346  return true;
347  }
348 
350 
351  std::vector<iteration::walker_base*> stack_;
352 };
353 
354 } // namespace order
355 
356 } // namespace policy
357 
358 } // namespace iteration
359 
360 } // namespace gui2
Define the common log macros for the gui toolkit.
#define ERR_GUI_E
Definition: log.hpp:37
When calling next the following it has the following results.
Definition: walker.hpp:68
When calling next the following it has the following results.
Definition: walker.hpp:57
std::vector< iteration::walker_base * > stack_
const std::string & id() const
Definition: widget.cpp:109
Helper class to select to visit or skip a level.
Base class for all widgets.
Definition: widget.hpp:49
Contains the exceptions thrown by the gui2::iteration::iterator classes.
Generic file dialog.
Definition: field-fwd.hpp:22
visit_level< VW, walker_base::self > visit_widget
visit_level< VC, walker_base::child > visit_child
The walker abstract base class.
Definition: walker.hpp:26
std::vector< iteration::walker_base * > stack_
visit_level< VW, walker_base::self > visit_widget
Thrown when moving an invalid iterator.
Definition: exception.hpp:56
#define TST_GUI_I
Definition: log.hpp:47
visit_level< VC, walker_base::child > visit_child
CURSOR_TYPE get()
Definition: cursor.cpp:215
visit_level< VG, walker_base::internal > visit_grid
#define ERR_GUI_I
Definition: log.hpp:51
#define next(ls)
Definition: llex.cpp:32
Thrown when deferring an invalid iterator.
Definition: exception.hpp:38
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
visit_level< VG, walker_base::internal > visit_grid