Freeciv21
Develop your civilization from humble roots to a global empire
tab_enablers.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 // Qt
15 #include <QGridLayout>
16 #include <QLineEdit>
17 #include <QListWidget>
18 #include <QMenu>
19 #include <QMessageBox>
20 #include <QPushButton>
21 #include <QToolButton>
22 
23 // utility
24 #include "fcintl.h"
25 #include "log.h"
26 
27 // common
28 #include "game.h"
29 #include "government.h"
30 
31 // ruledit
32 #include "ruledit.h"
33 #include "ruledit_qt.h"
34 #include "tab_enablers.h"
35 
37 public:
38  explicit fix_enabler_item(struct action_enabler *enabler);
39  virtual ~fix_enabler_item();
40  void close() override;
41 
42  const void *item() override;
43  void *item_working_copy() override;
44  const char *name() override;
45  struct req_vec_problem *find_next_problem() override;
46  void apply_accepted_changes() override;
47  void undo_accepted_changes() override;
48  int num_vectors() override;
51  bool vector_in_item(const struct requirement_vector *vec) override;
52 
53 private:
56  QString my_name;
57 };
58 
66 {
67  struct req_vec_problem *problem = action_enabler_suggest_repair(enabler);
68 
69  if (problem != nullptr) {
70  req_vec_problem_free(problem);
71  return RVPS_REPAIR;
72  }
73 
74  problem = action_enabler_suggest_improvement(enabler);
75  if (problem != nullptr) {
76  req_vec_problem_free(problem);
77  return RVPS_IMPROVE;
78  }
79 
80  return RVPS_NO_PROBLEM;
81 }
82 
87 {
88  QVBoxLayout *main_layout = new QVBoxLayout(this);
89  QGridLayout *enabler_layout = new QGridLayout();
90  QLabel *label;
91  QPushButton *add_button;
92 
93  ui = ui_in;
96 
97  selected = 0;
98 
99  enabler_list = new QListWidget(this);
100 
101  connect(enabler_list, &QListWidget::itemSelectionChanged, this,
103  main_layout->addWidget(enabler_list);
104 
105  enabler_layout->setSizeConstraint(QLayout::SetMaximumSize);
106 
107  label = new QLabel(QString::fromUtf8(R__("Type")));
108  label->setParent(this);
109  enabler_layout->addWidget(label, 0, 0);
110 
111  type_button = new QToolButton();
112  type_menu = new QMenu();
113 
114  action_iterate(act) { type_menu->addAction(action_id_rule_name(act)); }
116 
117  connect(type_menu, &QMenu::triggered, this, &tab_enabler::edit_type);
118 
119  type_button->setToolButtonStyle(Qt::ToolButtonTextOnly);
120  type_button->setPopupMode(QToolButton::MenuButtonPopup);
121 
122  type_button->setMenu(type_menu);
123 
124  type_button->setEnabled(false);
125  enabler_layout->addWidget(type_button, 0, 2);
126 
128  new QPushButton(QString::fromUtf8(R__("Actor Requirements")), this);
129  connect(act_reqs_button, &QAbstractButton::pressed, this,
131  act_reqs_button->setEnabled(false);
132  enabler_layout->addWidget(act_reqs_button, 1, 2);
133 
135  new QPushButton(QString::fromUtf8(R__("Target Requirements")), this);
136  connect(tgt_reqs_button, &QAbstractButton::pressed, this,
138  tgt_reqs_button->setEnabled(false);
139  enabler_layout->addWidget(tgt_reqs_button, 2, 2);
140 
141  add_button = new QPushButton(QString::fromUtf8(R__("Add Enabler")), this);
142  connect(add_button, &QAbstractButton::pressed, this,
144  enabler_layout->addWidget(add_button, 3, 0);
145  show_experimental(add_button);
146 
147  delete_button =
148  new QPushButton(QString::fromUtf8(R__("Remove this Enabler")), this);
149  connect(delete_button, &QAbstractButton::pressed, this,
151  delete_button->setEnabled(false);
152  enabler_layout->addWidget(delete_button, 3, 2);
154 
155  repair_button = new QPushButton(this);
156  connect(repair_button, &QAbstractButton::pressed, this,
158  repair_button->setEnabled(false);
159  enabler_layout->addWidget(repair_button, 3, 1);
160 
161  refresh();
162 
163  main_layout->addLayout(enabler_layout);
164 
165  setLayout(main_layout);
166 }
167 
172 {
173  int n = 0;
174 
175  enabler_list->clear();
176 
177  action_enablers_iterate(enabler)
178  {
179  if (!enabler->disabled) {
180  char buffer[512];
181  QListWidgetItem *item;
182 
183  fc_snprintf(buffer, sizeof(buffer), "#%d: %s", n,
185 
186  item = new QListWidgetItem(QString::fromUtf8(buffer));
187 
188  enabler_list->insertItem(n++, item);
189 
191 
192  item->setSelected(enabler == selected);
193  }
194  }
196 }
197 
202 {
203  int i = 0;
204 
205  selected = enabler;
206 
207  if (selected != nullptr) {
208  QString dispn =
209  QString::fromUtf8(action_rule_name(enabler_get_action(enabler)));
210 
211  type_button->setText(dispn);
212 
213  type_button->setEnabled(true);
214  act_reqs_button->setEnabled(true);
215  tgt_reqs_button->setEnabled(true);
216 
217  delete_button->setEnabled(true);
218 
219  switch (enabler_problem_level(selected)) {
220  case RVPS_REPAIR:
221  // Offer to repair the enabler if it has a problem.
222  // TRANS: Fix an error in an action enabler.
223  repair_button->setText(QString::fromUtf8(R__("Repair Enabler")));
224  repair_button->setEnabled(true);
225  break;
226  case RVPS_IMPROVE:
227  // TRANS: Fix a non error issue in an action enabler.
228  repair_button->setText(QString::fromUtf8(R__("Improve Enabler")));
229  repair_button->setEnabled(true);
230  break;
231  case RVPS_NO_PROBLEM:
232  repair_button->setText(QString::fromUtf8(R__("Enabler Issues")));
233  repair_button->setEnabled(false);
234  break;
235  }
236  } else {
237  type_button->setText(QStringLiteral("None"));
238  type_button->setEnabled(false);
239 
240  act_reqs_button->setEnabled(false);
241  tgt_reqs_button->setEnabled(false);
242 
243  repair_button->setEnabled(false);
244  repair_button->setText(QString::fromUtf8(R__("Enabler Issues")));
245 
246  delete_button->setEnabled(false);
247  }
248 
249  // The enabler may have gotten (rid of) a problem.
250  action_enablers_iterate(enabler)
251  {
252  QListWidgetItem *item = enabler_list->item(i++);
253 
254  if (item == nullptr) {
255  continue;
256  }
257 
259  }
261 }
262 
267 {
268  int i = 0;
269 
270  action_enablers_iterate(enabler)
271  {
272  QListWidgetItem *item = enabler_list->item(i++);
273 
274  if (item != nullptr && item->isSelected()) {
275  update_enabler_info(enabler);
276  }
277  }
279 }
280 
285 {
286  if (selected != nullptr) {
287  selected->disabled = true;
288 
289  refresh();
290  update_enabler_info(nullptr);
291  }
292 }
293 
298 {
299  return true;
300 }
301 
306 {
307  struct action_enabler *new_enabler;
308 
309  // Try to reuse freed enabler slot
310  action_enablers_iterate(enabler)
311  {
312  if (enabler->disabled) {
313  if (initialize_new_enabler(enabler)) {
314  enabler->disabled = false;
315  update_enabler_info(enabler);
316  refresh();
317  }
318  return;
319  }
320  }
322 
323  // Try to add completely new enabler
324  new_enabler = action_enabler_new();
325 
327  return );
329  action_enabler_free(new_enabler);
330  return );
331  new_enabler->action = (NUM_ACTIONS - 1);
332 
333  action_enabler_add(new_enabler);
334 
335  update_enabler_info(new_enabler);
336  refresh();
337 }
338 
343 {
344  if (selected == nullptr) {
345  // Nothing to repair
346  return;
347  }
348 
350 }
351 
356 void tab_enabler::incoming_rec_vec_change(const requirement_vector *vec)
357 {
358  action_enablers_iterate(enabler)
359  {
360  if (&enabler->actor_reqs == vec || &enabler->target_reqs == vec) {
361  update_enabler_info(enabler);
362  }
363  }
365 }
366 
371 {
372  struct action *paction;
373  QByteArray an_bytes;
374 
375  an_bytes = action->text().toUtf8();
376  paction = action_by_rule_name(an_bytes.data());
377 
378  if (selected != nullptr && paction != nullptr) {
379  // Must remove and add back because enablers are stored by action.
381  selected->action = paction->id;
383 
384  // Show the changes.
386  refresh();
387  }
388 }
389 
394 {
395  if (selected != nullptr) {
396  ui->open_req_edit(QString::fromUtf8(R__("Enabler (target)")),
398  }
399 }
400 
405 {
406  if (selected != nullptr) {
407  ui->open_req_edit(QString::fromUtf8(R__("Enabler (actor)")),
408  &selected->actor_reqs);
409  }
410 }
411 
417  : current_enabler(nullptr), local_copy(nullptr)
418 {
419  char buf[MAX_LEN_NAME * 2];
420  struct action *paction = action_by_number(enabler->action);
421 
422  fc_assert_ret(paction);
423 
424  /* Can't use QString::asprintf() as msys libintl.h defines asprintf()
425  * as a macro */
426  fc_snprintf(buf, sizeof(buf), R__("action enabler for %s"),
427  action_rule_name(paction));
428 
429  // Don't modify the original until the user accepts
430  local_copy = action_enabler_copy(enabler);
431  current_enabler = enabler;
432 
433  // As precise a title as possible
434  my_name = QString(buf);
435 }
436 
441 
445 void fix_enabler_item::close() { delete this; }
446 
451 const void *fix_enabler_item::item() { return current_enabler; }
452 
458 
465 const char *fix_enabler_item::name() { return my_name.toUtf8().data(); }
466 
473 {
475  if (out != nullptr) {
476  return out;
477  }
478 
480 }
481 
489 {
490  // The user has approved the solution
492  requirement_vector_copy(&current_enabler->actor_reqs,
494  requirement_vector_copy(&current_enabler->target_reqs,
496 }
497 
504 {
505  // The user has rejected all solutions
507  requirement_vector_copy(&local_copy->actor_reqs,
509  requirement_vector_copy(&local_copy->target_reqs,
511 }
512 
517 int fix_enabler_item::num_vectors() { return 2; }
518 
526 {
528 }
529 
537 {
539 }
540 
546 bool fix_enabler_item::vector_in_item(const struct requirement_vector *vec)
547 {
548  return (&current_enabler->actor_reqs == vec
549  || &current_enabler->target_reqs == vec);
550 }
const char * action_rule_name(const struct action *action)
Get the rule name of the action.
Definition: actions.cpp:1343
struct action_enabler * action_enabler_copy(const struct action_enabler *original)
Create a new copy of an existing action enabler.
Definition: actions.cpp:1839
struct req_vec_problem * action_enabler_suggest_repair(const struct action_enabler *enabler)
Returns a suggestion to fix the specified action enabler or nullptr if no fix is found to be needed.
Definition: actions.cpp:2187
void action_enabler_free(struct action_enabler *enabler)
Free resources allocated for the action enabler.
Definition: actions.cpp:1827
struct action * action_by_rule_name(const char *name)
Return the action with the given name.
Definition: actions.cpp:1169
struct requirement_vector * action_enabler_vector_by_number(const void *enabler, req_vec_num_in_item number)
Returns a writable pointer to the specified requirement vector in the action enabler or nullptr if th...
Definition: actions.cpp:2325
struct action_enabler * action_enabler_new()
Create a new action enabler.
Definition: actions.cpp:1810
void action_enabler_add(struct action_enabler *enabler)
Add an action enabler to the current ruleset.
Definition: actions.cpp:1854
struct action * action_by_number(action_id act_id)
Return the action with the given id.
Definition: actions.cpp:1149
struct req_vec_problem * action_enabler_suggest_improvement(const struct action_enabler *enabler)
Returns a suggestion to improve the specified action enabler or nullptr if nothing to improve is foun...
Definition: actions.cpp:2251
bool action_id_exists(const action_id act_id)
Returns TRUE iff the specified action ID refers to a valid action.
Definition: actions.cpp:1138
bool action_enabler_remove(struct action_enabler *enabler)
Remove an action enabler from the current ruleset.
Definition: actions.cpp:1870
const char * action_enabler_vector_by_number_name(req_vec_num_in_item vec)
Returns the name of the given requirement vector number n in an action enabler or nullptr if enablers...
Definition: actions.cpp:2349
const char * action_id_rule_name(action_id act_id)
Get the rule name of the action.
Definition: actions.cpp:1362
#define action_enablers_iterate_end
Definition: actions.h:425
#define enabler_get_action(_enabler_)
Definition: actions.h:369
#define NUM_ACTIONS
Definition: actions.h:224
#define action_iterate_end
Definition: actions.h:383
#define action_enablers_iterate(_enabler_)
Definition: actions.h:417
#define action_iterate(_act_)
Definition: actions.h:378
requirement_vector_namer vector_namer() override
Returns a function pointer to a function that names this item kind's requirement vector number number...
fix_enabler_item(struct action_enabler *enabler)
Construct fix_enabler_item to help req_vec_fix with the action enabler unique stuff.
void close() override
Tell the helper that it has outlived its usefulnes.
const void * item() override
Returns a pointer to the ruleset item.
int num_vectors() override
Returns the number of requirement vectors in this item.
virtual ~fix_enabler_item()
Destructor for fix_enabler_item.
struct action_enabler * local_copy
bool vector_in_item(const struct requirement_vector *vec) override
Check if the specified vector belongs to this item.
void undo_accepted_changes() override
Undo all the changes the user has accepted to the ruleset item.
requirement_vector_by_number vector_getter() override
Returns a function pointer to a function that returns a writable pointer to the specified requirement...
void * item_working_copy() override
Returns a pointer to the working copy of the ruleset item.
void apply_accepted_changes() override
Do all the changes the user has accepted to the ruleset item.
struct action_enabler * current_enabler
struct req_vec_problem * find_next_problem() override
Returns the next detected requirement vector problem for the ruleset item or nullptr if no fix is fou...
const char * name() override
Returns a name to describe the item, hopefully good enough to distinguish it from other items.
Ruleset entity specific methods for the ruleset item having its requirements fixed.
Definition: req_vec_fix.h:44
void open_req_vec_fix(req_vec_fix_item *item_info)
Open req_vec_fix dialog.
Definition: ruledit_qt.cpp:313
void rec_vec_may_have_changed(const requirement_vector *vec)
A requirement vector may have been changed.
void open_req_edit(const QString &target, struct requirement_vector *preqs)
Open req_edit dialog.
Definition: ruledit_qt.cpp:278
ruledit_gui * ui
Definition: tab_enablers.h:43
void delete_now()
User requested enabler deletion.
void refresh()
Refresh the information.
void edit_type(QAction *action)
User selected action to enable.
struct action_enabler * selected
Definition: tab_enablers.h:55
QPushButton * act_reqs_button
Definition: tab_enablers.h:49
QToolButton * type_button
Definition: tab_enablers.h:47
void edit_actor_reqs()
User wants to edit actor reqs.
tab_enabler(ruledit_gui *ui_in)
Setup tab_enabler object.
QPushButton * tgt_reqs_button
Definition: tab_enablers.h:50
QMenu * type_menu
Definition: tab_enablers.h:48
void repair_now()
User requested enabler repair.
void edit_target_reqs()
User wants to edit target reqs.
void select_enabler()
User selected enabler from the list.
QListWidget * enabler_list
Definition: tab_enablers.h:53
QPushButton * delete_button
Definition: tab_enablers.h:51
bool initialize_new_enabler(struct action_enabler *enabler)
Initialize new enabler for use.
QPushButton * repair_button
Definition: tab_enablers.h:52
void update_enabler_info(struct action_enabler *enabler)
Update info of the enabler.
void add_now()
User requested new enabler.
void incoming_rec_vec_change(const requirement_vector *vec)
A requirement vector may have been changed.
#define MAX_LEN_NAME
Definition: fc_types.h:61
#define R__(String)
Definition: fcintl.h:58
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert_action(condition, action)
Definition: log.h:104
void mark_item(QListWidgetItem *item, enum req_vec_problem_seriousness problem_level)
Mark a ruleset item in a list as having a problem.
Definition: req_vec_fix.cpp:32
req_vec_problem_seriousness
Definition: req_vec_fix.h:31
@ RVPS_NO_PROBLEM
Definition: req_vec_fix.h:32
@ RVPS_REPAIR
Definition: req_vec_fix.h:34
@ RVPS_IMPROVE
Definition: req_vec_fix.h:33
void req_vec_problem_free(struct req_vec_problem *issue)
De-allocates resources associated with the given requirement vector problem.
struct requirement_vector *(* requirement_vector_by_number)(const void *parent_item, req_vec_num_in_item number)
Returns a writable pointer to the specified requirement vector in the specified parent item or nullpt...
Definition: requirements.h:164
const char *(* requirement_vector_namer)(req_vec_num_in_item number)
Returns the name of the specified requirement vector number in the parent item or nullptr if parent i...
Definition: requirements.h:174
void show_experimental(QWidget *wdg)
Show widget if experimental features enabled, hide otherwise.
Definition: ruledit.cpp:163
bool disabled
Definition: actions.h:363
action_id action
Definition: actions.h:364
struct requirement_vector actor_reqs
Definition: actions.h:365
struct requirement_vector target_reqs
Definition: actions.h:366
action_id id
Definition: actions.h:306
Definition: climisc.h:66
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
static enum req_vec_problem_seriousness enabler_problem_level(struct action_enabler *enabler)
Returns how big a problem an action enabler has.