Freeciv21
Develop your civilization from humble roots to a global empire
view_economics.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 1996-2023 Freeciv21 and Freeciv contributors. This file is
3  part of Freeciv21. Freeciv21 is free software: you can redistribute it
4  and/or modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation, either version 3 of the
6  License, or (at your option) any later version. You should have received
7  a copy of the GNU General Public License along with Freeciv21. If not,
8  see https://www.gnu.org/licenses/.
9  */
10 
11 /*
12  * This file contains functions to generate the table based GUI for
13  * the economics view (formally known as the economy report).
14  */
15 
16 #include "views/view_economics.h"
17 // client
18 #include "fc_client.h"
19 #include "hudwidget.h"
20 #include "page_game.h"
21 #include "tileset/sprite.h"
22 #include "top_bar.h"
23 
28 {
29  ui.setupUi(this);
30 
31  QFont font = ui.eco_widget->horizontalHeader()->font();
32  font.setWeight(QFont::Bold);
33  ui.eco_widget->horizontalHeader()->setFont(font);
34 
35  QStringList slist;
36  slist << _("Type") << Q_("?Building or Unit type:Name") << _("Redundant")
37  << _("Count") << _("Cost") << _("Total Upkeep")
38  << _("Redundant Cities");
39 
40  ui.eco_widget->setColumnCount(slist.count());
41  ui.eco_widget->setHorizontalHeaderLabels(slist);
42  ui.eco_widget->setAlternatingRowColors(true);
43  ui.bdisband->setText(_("Disband"));
44  ui.bsell->setText(_("Sell All"));
45  ui.bredun->setText(_("Sell Redundant"));
46 
47  connect(ui.bdisband, &QAbstractButton::pressed, this,
49  connect(ui.bsell, &QAbstractButton::pressed, this,
51  connect(ui.bredun, &QAbstractButton::pressed, this,
53  connect(ui.eco_widget->selectionModel(),
54  &QItemSelectionModel::selectionChanged, this,
56  setLayout(ui.eco_layout);
57  queen()->gimmePlace(this, QStringLiteral("ECO"));
58  index = queen()->addGameTab(this);
59 }
60 
64 eco_report::~eco_report() { queen()->removeRepoDlg(QStringLiteral("ECO")); }
65 
69 void eco_report::init() { queen()->game_tab_widget->setCurrentIndex(index); }
70 
75 {
76  struct improvement_entry building_entries[B_LAST];
77  struct unit_entry unit_entries[U_LAST];
78  int entries_used, building_total, unit_total, tax, i, j;
79  QString buf;
80  QTableWidgetItem *item;
81  QFont f = QApplication::font();
82  QFontMetrics fm(f);
83  int h = fm.height() + 24;
84 
85  ui.eco_widget->setRowCount(0);
86  ui.eco_widget->clearContents();
87  get_economy_report_data(building_entries, &entries_used, &building_total,
88  &tax);
89  for (i = 0; i < entries_used; i++) {
90  struct improvement_entry *pentry = building_entries + i;
91  struct impr_type *pimprove = pentry->type;
92  cid id = cid_encode_building(pimprove);
93 
94  ui.eco_widget->insertRow(i);
95  for (j = 0; j < 7; j++) {
96  item = new QTableWidgetItem;
97  switch (j) {
98  case 0: {
99  auto sprite =
100  get_building_sprite(tileset, pimprove)->scaledToHeight(h);
101  QLabel *lbl = new QLabel;
102  lbl->setPixmap(QPixmap(sprite));
103  lbl->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
104  ui.eco_widget->setCellWidget(i, j, lbl);
105  item->setData(Qt::UserRole, id);
106  } break;
107  case 1:
108  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
109  item->setText(improvement_name_translation(pimprove));
110  break;
111  case 2:
112  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
113  item->setData(Qt::DisplayRole, pentry->redundant);
114  break;
115  case 3:
116  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
117  item->setData(Qt::DisplayRole, pentry->count);
118  break;
119  case 4:
120  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
121  item->setData(Qt::DisplayRole, pentry->cost);
122  break;
123  case 5:
124  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
125  item->setData(Qt::DisplayRole, pentry->total_cost);
126  break;
127  case 6:
128  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
129  item->setData(Qt::DisplayRole, pentry->city_names);
130  }
131  ui.eco_widget->setItem(i, j, item);
132  }
133  }
134  max_row = i;
135  get_economy_report_units_data(unit_entries, &entries_used, &unit_total);
136  for (i = 0; i < entries_used; i++) {
137  struct unit_entry *pentry = unit_entries + i;
138  struct unit_type *putype = pentry->type;
139  cid id = cid_encode_unit(putype);
140 
141  ui.eco_widget->insertRow(i + max_row);
142  for (j = 0; j < 7; j++) {
143  item = new QTableWidgetItem;
144  switch (j) {
145  case 0: {
146  auto sprite =
147  get_unittype_sprite(tileset, putype, direction8_invalid())
148  ->scaledToHeight(h);
149  QLabel *lbl = new QLabel;
150  lbl->setPixmap(QPixmap(sprite));
151  lbl->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
152  ui.eco_widget->setCellWidget(max_row + i, j, lbl);
153  }
154  item->setData(Qt::UserRole, id);
155  break;
156  case 1:
157  item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
158  item->setText(utype_name_translation(putype));
159  break;
160  case 2:
161  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
162  item->setData(Qt::DisplayRole, 0);
163  break;
164  case 3:
165  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
166  item->setData(Qt::DisplayRole, pentry->count);
167  break;
168  case 4:
169  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
170  item->setData(Qt::DisplayRole, pentry->cost);
171  break;
172  case 5:
173  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
174  item->setData(Qt::DisplayRole, pentry->total_cost);
175  break;
176  case 6:
177  item->setTextAlignment(Qt::AlignVCenter | Qt::AlignLeft);
178  item->setText(_("Not Applicable"));
179  }
180  ui.eco_widget->setItem(max_row + i, j, item);
181  }
182  }
183  max_row = max_row + i;
184  buf = QString(_("Income: %1 Total Costs: %2"))
185  .arg(QString::number(tax),
186  QString::number(building_total + unit_total));
187  ui.eco_label->setText(buf);
188 
189  // Resize all columns except the last (which we want to wrap).
190  for (int i = 0; i < ui.eco_widget->columnCount() - 1; ++i) {
191  ui.eco_widget->resizeColumnToContents(i);
192  }
193  // Resize rows to let text wrap around.
194  ui.eco_widget->resizeRowsToContents();
195 }
196 
200 void eco_report::selection_changed(const QItemSelection &sl,
201  const QItemSelection &ds)
202 {
203  QTableWidgetItem *itm;
204  int i;
205  QVariant qvar;
206  struct universal selected;
207  const struct impr_type *pimprove;
208  ui.bdisband->setEnabled(false);
209  ui.bsell->setEnabled(false);
210  ui.bredun->setEnabled(false);
211 
212  if (sl.isEmpty()) {
213  return;
214  }
215 
216  curr_row = sl.indexes().at(0).row();
217  if (curr_row >= 0 && curr_row <= max_row) {
218  itm = ui.eco_widget->item(curr_row, 0);
219  qvar = itm->data(Qt::UserRole);
220  uid = qvar.toInt();
221  selected = cid_decode(uid);
222  switch (selected.kind) {
223  case VUT_IMPROVEMENT:
224  pimprove = selected.value.building;
225  counter = ui.eco_widget->item(curr_row, 3)->text().toInt();
226  if (can_sell_building(pimprove)) {
227  ui.bsell->setEnabled(true);
228  }
229  itm = ui.eco_widget->item(curr_row, 2);
230  i = itm->text().toInt();
231  if (i > 0) {
232  ui.bredun->setEnabled(true);
233  }
234  break;
235  case VUT_UTYPE:
236  counter = ui.eco_widget->item(curr_row, 3)->text().toInt();
237  ui.bdisband->setEnabled(true);
238  break;
239  default:
240  qCritical("Not supported type: %d.", selected.kind);
241  }
242  }
243 }
244 
249 {
250  struct universal selected;
251  QString buf;
252  hud_message_box *ask = new hud_message_box(king()->central_wdg);
253  Unit_type_id utype;
254 
255  selected = cid_decode(uid);
256  utype = utype_number(selected.value.utype);
257  buf = QString(_("Do you really wish to disband every %1 (%2 total)?"))
259  QString::number(counter));
260 
261  ask->set_text_title(buf, _("Disband Units?"));
262  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
263  ask->setDefaultButton(QMessageBox::Cancel);
264  ask->button(QMessageBox::Yes)->setText(_("Yes Disband"));
265  ask->setAttribute(Qt::WA_DeleteOnClose);
266  connect(ask, &hud_message_box::accepted, [=]() {
267  struct unit_type *putype = utype_by_number(utype);
268  char buf[1024];
269  hud_message_box *result;
270 
271  if (putype) {
272  disband_all_units(putype, false, buf, sizeof(buf));
273  result = new hud_message_box(king()->central_wdg);
274  result->set_text_title(buf, _("Disband Results"));
275  result->setStandardButtons(QMessageBox::Ok);
276  result->setAttribute(Qt::WA_DeleteOnClose);
277  result->show();
278  }
279  });
280  ask->show();
281 }
282 
287 {
288  struct universal selected;
289  QString buf;
290  hud_message_box *ask = new hud_message_box(king()->central_wdg);
291  const struct impr_type *pimprove;
292  Impr_type_id impr_id;
293 
294  selected = cid_decode(uid);
295  pimprove = selected.value.building;
296  impr_id = improvement_number(pimprove);
297 
298  buf = QString(_("Do you really wish to sell "
299  "every %1 (%2 total)?"))
300  .arg(improvement_name_translation(pimprove),
301  QString::number(counter));
302 
303  ask->set_text_title(buf, _("Sell Improvements?"));
304  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
305  ask->setDefaultButton(QMessageBox::Cancel);
306  ask->button(QMessageBox::Yes)->setText(_("Yes Sell"));
307  ask->setAttribute(Qt::WA_DeleteOnClose);
308  connect(ask, &hud_message_box::accepted, [=]() {
309  char buf[1024];
310  hud_message_box *result;
311  struct impr_type *pimprove = improvement_by_number(impr_id);
312 
313  if (!pimprove) {
314  return;
315  }
316 
317  sell_all_improvements(pimprove, false, buf, sizeof(buf));
318 
319  result = new hud_message_box(king()->central_wdg);
320  result->set_text_title(buf, _("Sell Results"));
321  result->setStandardButtons(QMessageBox::Ok);
322  result->setAttribute(Qt::WA_DeleteOnClose);
323  result->show();
324  });
325  ask->show();
326 }
327 
332 {
333  struct universal selected;
334  QString s, buf;
335  hud_message_box *ask = new hud_message_box(king()->central_wdg);
336  const struct impr_type *pimprove;
337  Impr_type_id impr_id;
338 
339  selected = cid_decode(uid);
340  pimprove = selected.value.building;
341  impr_id = improvement_number(pimprove);
342 
343  buf = QString::asprintf(_("Do you really wish to sell "
344  "every redundant %s (%d total)?"),
346 
347  ask->set_text_title(s, _("Sell Redundant Improvements?"));
348  ask->setStandardButtons(QMessageBox::Cancel | QMessageBox::Yes);
349  ask->setDefaultButton(QMessageBox::Cancel);
350  ask->button(QMessageBox::Yes)->setText(_("Yes Sell"));
351  ask->setAttribute(Qt::WA_DeleteOnClose);
352  connect(ask, &hud_message_box::accepted, [=]() {
353  char buf[1024];
354  hud_message_box *result;
355  struct impr_type *pimprove = improvement_by_number(impr_id);
356 
357  if (!pimprove) {
358  return;
359  }
360 
361  sell_all_improvements(pimprove, true, buf, sizeof(buf));
362 
363  result = new hud_message_box(king()->central_wdg);
364  result->set_text_title(buf, _("Sell Redundant Results"));
365  result->setStandardButtons(QMessageBox::Ok);
366  result->setAttribute(Qt::WA_DeleteOnClose);
367  result->show();
368  });
369  ask->show();
370 }
371 
376 {
377  int i;
378  eco_report *eco_rep;
379  QWidget *w;
380 
381  if (queen()->isRepoDlgOpen(QStringLiteral("ECO"))) {
382  i = queen()->gimmeIndexOf(QStringLiteral("ECO"));
383  if (queen()->game_tab_widget->currentIndex() == i) {
384  w = queen()->game_tab_widget->widget(i);
385  eco_rep = reinterpret_cast<eco_report *>(w);
386  eco_rep->update_report();
387  }
388  }
390 }
391 
396 {
397  int i;
398  eco_report *eco_rep;
399  QWidget *w;
400  if (!queen()->isRepoDlgOpen(QStringLiteral("ECO"))) {
401  eco_rep = new eco_report;
402  eco_rep->init();
403  eco_rep->update_report();
404  } else {
405  i = queen()->gimmeIndexOf(QStringLiteral("ECO"));
406  fc_assert(i != -1);
407  w = queen()->game_tab_widget->widget(i);
408  if (w->isVisible()) {
410  return;
411  }
412  eco_rep = reinterpret_cast<eco_report *>(w);
413  eco_rep->update_report();
414  queen()->game_tab_widget->setCurrentWidget(eco_rep);
415  }
416 }
417 
422 {
423  int i;
424  eco_report *eco_rep;
425  QWidget *w;
426 
427  if (queen()->isRepoDlgOpen(QStringLiteral("ECO"))) {
428  i = queen()->gimmeIndexOf(QStringLiteral("ECO"));
429  fc_assert(i != -1);
430  w = queen()->game_tab_widget->widget(i);
431  eco_rep = reinterpret_cast<eco_report *>(w);
432  eco_rep->deleteLater();
433  }
434 }
eco_report()
Constructor for economy report.
void selection_changed(const QItemSelection &sl, const QItemSelection &ds)
Action for selection changed in economy report.
void disband_units()
Disband pointed units (in economy report)
void sell_buildings()
Sell all pointed builings.
void init()
Initializes place in tab for economy report.
Ui::FormEconomyReport ui
~eco_report()
Destructor for economy report.
void sell_redundant()
Sells redundant buildings.
void update_report()
Refresh all widgets for economy report.
void set_text_title(const QString &s1, const QString &s2)
Sets text and title and shows message box.
Definition: hudwidget.cpp:117
int gimmeIndexOf(const QString &str)
Returns index on game tab page of given report dialog.
Definition: page_game.cpp:706
int addGameTab(QWidget *widget)
Inserts tab widget to game view page.
Definition: page_game.cpp:670
void removeRepoDlg(const QString &str)
Removes report dialog string from the list marking it as closed.
Definition: page_game.cpp:723
void updateSidebarTooltips()
Updates top bar tooltips.
Definition: page_game.cpp:340
void gimmePlace(QWidget *widget, const QString &str)
Finds not used index on game_view_tab and returns it.
Definition: page_game.cpp:690
fc_game_tab_widget * game_tab_widget
Definition: page_game.h:72
cid cid_encode_building(const struct impr_type *pimprove)
Encode a CID for the target building.
Definition: climisc.cpp:467
struct universal cid_decode(cid id)
Decode the CID into a city_production structure.
Definition: climisc.cpp:478
cid cid_encode_unit(const struct unit_type *punittype)
Encode a CID for the target unit type.
Definition: climisc.cpp:456
int cid
Definition: climisc.h:21
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
int Impr_type_id
Definition: fc_types.h:293
int Unit_type_id
Definition: fc_types.h:299
#define Q_(String)
Definition: fcintl.h:53
#define _(String)
Definition: fcintl.h:50
bool can_sell_building(const struct impr_type *pimprove)
Return TRUE iff the improvement can be sold.
struct impr_type * improvement_by_number(const Impr_type_id id)
Returns the improvement type for the given index/ID.
Impr_type_id improvement_number(const struct impr_type *pimprove)
Return the improvement index.
const char * improvement_name_translation(const struct impr_type *pimprove)
Return the (translated) name of the given improvement.
#define B_LAST
Definition: improvement.h:33
#define fc_assert(condition)
Definition: log.h:89
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
void get_economy_report_units_data(struct unit_entry *entries, int *num_entries_used, int *total_cost)
Returns an array of units with gold_upkeep.
void get_economy_report_data(struct improvement_entry *entries, int *num_entries_used, int *total_cost, int *total_income)
Fills out the array of struct improvement_entry given by entries.
void sell_all_improvements(const struct impr_type *pimprove, bool redundant_only, char *message, size_t message_sz)
Sell all improvements of the given type in all cities.
void disband_all_units(const struct unit_type *punittype, bool in_cities_only, char *message, size_t message_sz)
Disband all supported units of the given type.
int cost
QString city_names
struct impr_type * type
int total_cost
int count
int redundant
Definition: climisc.h:66
int total_cost
struct unit_type * type
int count
int cost
enum universals_n kind
Definition: fc_types.h:740
universals_u value
Definition: fc_types.h:739
const QPixmap * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum direction8 facing, const QColor &replace)
Return the sprite for the unit type (the base "unit" sprite).
Definition: tilespec.cpp:3416
const QPixmap * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Return the sprite for the building/improvement.
Definition: tilespec.cpp:3394
void top_bar_show_map()
Callback to show map.
Definition: top_bar.cpp:448
const struct unit_type * utype
Definition: fc_types.h:585
const struct impr_type * building
Definition: fc_types.h:579
struct unit_type * utype_by_number(const Unit_type_id id)
Return a pointer for the unit type struct for the given unit type id.
Definition: unittype.cpp:103
const char * utype_name_translation(const struct unit_type *punittype)
Return the (translated) name of the unit type.
Definition: unittype.cpp:1256
Unit_type_id utype_number(const struct unit_type *punittype)
Return the unit type index.
Definition: unittype.cpp:91
#define U_LAST
Definition: unittype.h:31
void real_economy_report_dialog_update(void *unused)
Update the economy report.
void popdown_economy_report()
Closes economy report.
void economy_report_dialog_popup()
Display the economy report.