Freeciv21
Develop your civilization from humble roots to a global empire
view_nations.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 nations view (formally known as the plrdlg - player dialog).
14  */
15 
16 #include "views/view_nations.h"
17 // Qt
18 #include <QMouseEvent>
19 #include <QPainter>
20 #include <QSortFilterProxyModel>
21 #include <qnamespace.h>
22 // utility
23 #include "astring.h"
24 #include "fcintl.h"
25 // common
26 #include "city.h"
27 #include "colors_common.h"
28 #include "game.h"
29 #include "government.h"
30 #include "icons.h"
31 #include "improvement.h"
32 #include "nation.h"
33 #include "research.h"
36 // client
37 #include "chatline_common.h"
38 #include "client_main.h"
39 #include "fc_client.h"
40 #include "fonts.h"
41 #include "page_game.h"
42 #include "tileset/sprite.h"
43 #include "tileset/tilespec.h"
44 #include "top_bar.h"
45 
49 static QRect
50 check_box_rect(const QStyleOptionViewItem &view_item_style_options)
51 {
52  QStyleOptionButton cbso;
53  QRect check_box_rect = QApplication::style()->subElementRect(
54  QStyle::SE_CheckBoxIndicator, &cbso);
55  QPoint check_box_point(view_item_style_options.rect.x()
56  + view_item_style_options.rect.width() / 2
57  - check_box_rect.width() / 2,
58  view_item_style_options.rect.y()
59  + view_item_style_options.rect.height() / 2
60  - check_box_rect.height() / 2);
61  return QRect(check_box_point, check_box_rect.size());
62 }
63 
67 QSize plr_item_delegate::sizeHint(const QStyleOptionViewItem &option,
68  const QModelIndex &index) const
69 {
70  return QItemDelegate::sizeHint(option, index);
71 }
72 
76 void plr_item_delegate::paint(QPainter *painter,
77  const QStyleOptionViewItem &option,
78  const QModelIndex &index) const
79 {
80  QStyleOptionButton but;
81  QStyleOptionButton cbso;
82  bool b;
83  QString str;
84  QRect rct;
85  QPixmap pix(16, 16);
86 
87  QStyleOptionViewItem opt = QItemDelegate::setOptions(index, option);
88  painter->save();
89  switch (player_dlg_columns[index.column()].type) {
90  case COL_FLAG:
91  QItemDelegate::drawBackground(painter, opt, index);
92  QItemDelegate::drawDecoration(painter, opt, option.rect,
93  index.data().value<QPixmap>());
94  break;
95  case COL_COLOR:
96  pix.fill(index.data().value<QColor>());
97  QItemDelegate::drawBackground(painter, opt, index);
98  QItemDelegate::drawDecoration(painter, opt, option.rect, pix);
99  break;
100  case COL_BOOLEAN:
101  b = index.data().toBool();
102  QItemDelegate::drawBackground(painter, opt, index);
103  cbso.state |= QStyle::State_Enabled;
104  if (b) {
105  cbso.state |= QStyle::State_On;
106  } else {
107  cbso.state |= QStyle::State_Off;
108  }
109  cbso.rect = check_box_rect(option);
110 
111  QApplication::style()->drawControl(QStyle::CE_CheckBox, &cbso, painter);
112  break;
113  case COL_GOVERNMENT:
114  case COL_TEXT:
115  QItemDelegate::paint(painter, option, index);
116  break;
117  case COL_RIGHT_TEXT:
118  QItemDelegate::drawBackground(painter, opt, index);
119  opt.displayAlignment = Qt::AlignRight;
120  rct = option.rect;
121  rct.setTop((rct.top() + rct.bottom()) / 2
122  - opt.fontMetrics.height() / 2);
123  rct.setBottom((rct.top() + rct.bottom()) / 2
124  + opt.fontMetrics.height() / 2);
125  if (index.data().toInt() == -1) {
126  str = QStringLiteral("?");
127  } else {
128  str = index.data().toString();
129  }
130  QItemDelegate::drawDisplay(painter, opt, rct, str);
131  break;
132  default:
133  QItemDelegate::paint(painter, option, index);
134  }
135  painter->restore();
136 }
137 
141 plr_item::plr_item(struct player *pplayer) : QObject()
142 {
143  ipplayer = pplayer;
144 }
145 
149 bool plr_item::setData(int column, const QVariant &value, int role)
150 {
151  Q_UNUSED(role)
152  return false;
153 }
154 
158 QVariant plr_item::data(int column, int role) const
159 {
160  QString str;
161 
162  if (role == Qt::UserRole) {
163  return QVariant::fromValue((void *) ipplayer);
164  }
165 
166  const auto pdc = &player_dlg_columns[column];
167  if (role != Qt::DisplayRole && pdc->type != COL_GOVERNMENT) {
168  return QVariant();
169  }
170 
171  switch (pdc->type) {
172  case COL_FLAG: {
174  auto fm = std::make_unique<QFontMetrics>(f);
176  ->scaledToHeight(fm->height());
177  } break;
178  case COL_COLOR:
180  break;
181  case COL_BOOLEAN:
182  return pdc->bool_func(ipplayer);
183  break;
184  case COL_GOVERNMENT:
185  if (role == Qt::DisplayRole) {
186  return pdc->func(ipplayer);
187  } else if (role == Qt::DecorationRole
188  && BV_ISSET(ipplayer->client.visible, NI_GOVERNMENT)) {
190  } else {
191  return QVariant();
192  }
193  break;
194  case COL_TEXT:
195  return pdc->func(ipplayer);
196  break;
197  case COL_RIGHT_TEXT:
198  str = pdc->func(ipplayer);
199  if (str.toInt() != 0) {
200  return str.toInt();
201  } else if (str == QLatin1String("?")) {
202  return -1;
203  }
204  return str;
205  }
206 
207  return QVariant();
208 }
209 
213 plr_model::plr_model(QObject *parent) : QAbstractListModel(parent)
214 {
215  populate();
216 }
217 
222 {
223  qDeleteAll(plr_list);
224  plr_list.clear();
225 }
226 
230 QVariant plr_model::data(const QModelIndex &index, int role) const
231 {
232  if (!index.isValid()) {
233  return QVariant();
234  }
235  if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0
236  && index.column() < columnCount()) {
237  return plr_list[index.row()]->data(index.column(), role);
238  }
239  return QVariant();
240 }
241 
245 QVariant plr_model::headerData(int section, Qt::Orientation orientation,
246  int role) const
247 {
248  struct player_dlg_column *pcol;
249  if (orientation == Qt::Horizontal && section < num_player_dlg_columns) {
250  if (role == Qt::DisplayRole) {
251  pcol = &player_dlg_columns[section];
252  return pcol->title;
253  }
254  }
255  return QVariant();
256 }
257 
261 bool plr_model::setData(const QModelIndex &index, const QVariant &value,
262  int role)
263 {
264  if (!index.isValid() || role != Qt::DisplayRole) {
265  return false;
266  }
267  if (index.row() >= 0 && index.row() < rowCount() && index.column() >= 0
268  && index.column() < columnCount()) {
269  bool change =
270  plr_list[index.row()]->setData(index.column(), value, role);
271  if (change) {
272  notify_plr_changed(index.row());
273  }
274  return change;
275  }
276  return false;
277 }
278 
283 {
284  emit dataChanged(index(row, 0), index(row, columnCount() - 1));
285 }
286 
291 {
292  plr_item *pi;
293 
294  qDeleteAll(plr_list);
295  plr_list.clear();
296  beginResetModel();
297  players_iterate(pplayer)
298  {
299  if ((is_barbarian(pplayer))) {
300  continue;
301  }
302  pi = new plr_item(pplayer);
303  plr_list << pi;
304  }
306  endResetModel();
307 }
308 
312 plr_widget::plr_widget(QWidget *widget) : QTableView(widget)
313 {
314  other_player = nullptr;
315  selected_player = nullptr;
316  pid = new plr_item_delegate(this);
317  setItemDelegate(pid);
318  list_model = new plr_model(this);
319 
321  filter_model->setDynamicSortFilter(true);
322  filter_model->setSourceModel(list_model);
323  filter_model->setFilterRole(Qt::DisplayRole);
324  QCollator coll;
325  coll.setCaseSensitivity(Qt::CaseInsensitive);
326  coll.setLocale(locale());
327  coll.setNumericMode(true);
328  filter_model->set_collator(coll);
329  setModel(filter_model);
330  sortByColumn(0, Qt::AscendingOrder); // Sort players alphabetically
331 
332  setSortingEnabled(true);
333  setSelectionMode(QAbstractItemView::SingleSelection);
334  setAutoScroll(true);
335  setAlternatingRowColors(true);
336 
337  auto header = horizontalHeader();
338  header->setContextMenuPolicy(Qt::CustomContextMenu);
339  header->setStretchLastSection(true);
340  hide_columns();
341  connect(header, &QWidget::customContextMenuRequested, this,
343 
344  connect(selectionModel(), &QItemSelectionModel::selectionChanged, this,
346 }
347 
353 {
354  QItemSelection selection;
355  QModelIndex i;
356  struct player *pplayer;
357  QVariant qvar;
358 
359  if (selected_player == nullptr) {
360  return;
361  }
362  for (int j = 0; j < filter_model->rowCount(); j++) {
363  i = filter_model->index(j, 0);
364  qvar = i.data(Qt::UserRole);
365  if (qvar.isNull()) {
366  continue;
367  }
368  pplayer = reinterpret_cast<struct player *>(qvar.value<void *>());
369  if (selected_player == pplayer) {
370  selection.append(QItemSelectionRange(i));
371  }
372  }
373  selectionModel()->select(selection,
374  QItemSelectionModel::Rows
375  | QItemSelectionModel::SelectCurrent);
376 }
377 
382 {
383  QMenu *hideshow_column = new QMenu(this);
384  hideshow_column->setTitle(_("Column visibility"));
385  QList<QAction *> actions;
386  for (int i = 0; i < list_model->columnCount(); ++i) {
387  QAction *myAct = hideshow_column->addAction(
388  list_model->headerData(i, Qt::Horizontal, Qt::DisplayRole)
389  .toString());
390  myAct->setCheckable(true);
391  myAct->setChecked(!isColumnHidden(i));
392  actions.append(myAct);
393  }
394 
395  hideshow_column->setAttribute(Qt::WA_DeleteOnClose);
396  connect(hideshow_column, &QMenu::triggered, this, [=](QAction *act) {
397  int col;
398  struct player_dlg_column *pcol;
399 
400  if (!act) {
401  return;
402  }
403 
404  col = actions.indexOf(act);
405  fc_assert_ret(col >= 0);
406  pcol = &player_dlg_columns[col];
407  pcol->show = !pcol->show;
408  setColumnHidden(col, !isColumnHidden(col));
409  if (!isColumnHidden(col) && columnWidth(col) <= 5) {
410  setColumnWidth(col, 100);
411  }
412  });
413 
414  hideshow_column->popup(QCursor::pos());
415 }
416 
420 QVariant plr_model::hide_data(int section) const
421 {
422  struct player_dlg_column *pcol;
423  pcol = &player_dlg_columns[section];
424  return pcol->show;
425 }
426 
431 {
432  int col;
433 
434  for (col = 0; col < list_model->columnCount(); col++) {
435  if (!list_model->hide_data(col).toBool()) {
436  setColumnHidden(col, !isColumnHidden(col));
437  }
438  }
439 }
440 
444 void plr_widget::nation_selected(const QItemSelection &sl,
445  const QItemSelection &ds)
446 {
447  Q_UNUSED(ds)
448  QModelIndex index;
449  QVariant qvar;
450  QModelIndexList indexes = sl.indexes();
451  struct city *pcity;
452  const struct player_diplstate *state;
453  struct research *my_research, *research;
454  char tbuf[256];
455  QString res;
456  QString sp = QStringLiteral(" ");
457  QString etax, esci, elux, egold, egov;
458  QString cult;
459  QString nl = QStringLiteral("<br>");
460  QStringList sorted_list_a;
461  QStringList sorted_list_b;
462  struct player *pplayer;
463  int a, b;
464  bool added;
465  bool entry_exist = false;
466  struct player *me;
467  Tech_type_id tech_id;
468  bool global_observer = client_is_global_observer();
469 
470  other_player = nullptr;
471  intel_str.clear();
472  tech_str.clear();
473  ally_str.clear();
474  if (indexes.isEmpty()) {
475  selected_player = nullptr;
476  plr->update_report(false);
477  return;
478  }
479  index = indexes.at(0);
480  qvar = index.data(Qt::UserRole);
481  pplayer = reinterpret_cast<player *>(qvar.value<void *>());
482  selected_player = pplayer;
483  other_player = pplayer;
484  if (!pplayer->is_alive) {
485  plr->update_report(false);
486  return;
487  }
488  me = client_player();
489  pcity = player_primary_capital(pplayer);
490  research = research_get(pplayer);
491 
492  switch (research->researching) {
493  case A_UNKNOWN:
494  res = _("(Unknown)");
495  break;
496  case A_UNSET:
497  if (BV_ISSET(pplayer->client.visible, NI_TECHS)) {
498  res = _("(none)");
499  } else {
500  res = _("(Unknown)");
501  }
502  break;
503  default:
506  + sp + "(" + QString::number(research->bulbs_researched) + "/"
507  + QString::number(research->client.researching_cost) + ")";
508  break;
509  }
510  if (BV_ISSET(pplayer->client.visible, NI_TAX_RATES)) {
511  etax = QString::number(pplayer->economic.tax) + "%";
512  esci = QString::number(pplayer->economic.science) + "%";
513  elux = QString::number(pplayer->economic.luxury) + "%";
514  } else {
515  etax = _("(Unknown)");
516  esci = _("(Unknown)");
517  elux = _("(Unknown)");
518  }
519  if (BV_ISSET(pplayer->client.visible, NI_CULTURE)) {
520  cult = QString::number(pplayer->client.culture);
521  } else {
522  cult = _("(Unknown)");
523  }
524  if (BV_ISSET(pplayer->client.visible, NI_GOLD)) {
525  egold = QString::number(pplayer->economic.gold);
526  } else {
527  egold = _("(Unknown)");
528  }
529  if (BV_ISSET(pplayer->client.visible, NI_GOVERNMENT)) {
530  egov = QString(government_name_for_player(pplayer));
531  } else {
532  egov = _("(Unknown)");
533  }
534 
535  intel_str = QStringLiteral("<table>");
536  QString line = QStringLiteral("<tr><td><b>%1</b></td><td>%2</td></tr>");
537 
538  intel_str +=
539  line.arg(_("Nation:"))
540  .arg(
541  QString(nation_adjective_for_player(pplayer)).toHtmlEscaped());
542  intel_str +=
543  line.arg(_("Ruler:"))
544  .arg(QString(ruler_title_for_player(pplayer, tbuf, sizeof(tbuf)))
545  .toHtmlEscaped());
546  intel_str += line.arg(_("Government:")).arg(egov.toHtmlEscaped());
547  intel_str +=
548  line.arg(_("Capital:"))
549  .arg(QString(((!pcity) ? _("(Unknown)") : city_name_get(pcity)))
550  .toHtmlEscaped());
551  intel_str += line.arg(_("Gold:")).arg(egold.toHtmlEscaped());
552  intel_str += line.arg(_("Tax:")).arg(etax.toHtmlEscaped());
553  intel_str += line.arg(_("Science:")).arg(esci.toHtmlEscaped());
554  intel_str += line.arg(_("Luxury:")).arg(elux.toHtmlEscaped());
555  intel_str += line.arg(_("Researching:")).arg(res.toHtmlEscaped());
556  intel_str += line.arg(_("Culture:")).arg(cult.toHtmlEscaped());
557  intel_str += QLatin1String("</table>");
558 
559  for (int i = 0; i < static_cast<int>(DS_LAST); i++) {
560  added = false;
561  if (entry_exist) {
562  ally_str += QLatin1String("<br>");
563  }
564  entry_exist = false;
565  players_iterate_alive(other)
566  {
567  if (other == pplayer || is_barbarian(other)) {
568  continue;
569  }
570  if (!BV_ISSET(pplayer->client.visible, NI_DIPLOMACY)
571  && !BV_ISSET(other->client.visible, NI_DIPLOMACY)) {
572  // We don't know anything about diplomatic relations between these
573  // players
574  continue;
575  }
576 
577  state = player_diplstate_get(pplayer, other);
578  if (static_cast<int>(state->type) == i) {
579  if (!added) {
580  ally_str = ally_str + QStringLiteral("<b>")
581  + QString(diplstate_type_translated_name(
582  static_cast<diplstate_type>(i)))
583  .toHtmlEscaped()
584  + ": " + QStringLiteral("</b>") + nl;
585  added = true;
586  }
587  if (gives_shared_vision(pplayer, other)) {
588  ally_str = ally_str + "(◐‿◑)";
589  }
591  + QString(nation_plural_for_player(other)).toHtmlEscaped()
592  + ", ";
593  entry_exist = true;
594  }
595  }
597  if (entry_exist) {
598  ally_str.replace(ally_str.lastIndexOf(QLatin1String(",")), 1,
599  QStringLiteral("."));
600  }
601  }
602  my_research = research_get(me);
603  if (!global_observer && BV_ISSET(pplayer->client.visible, NI_TECHS)) {
604  a = 0;
605  b = 0;
606  techs_known =
607  QString(_("<b>Techs unknown by %1:</b> "))
608  .arg(QString(nation_plural_for_player(pplayer)).toHtmlEscaped());
609  techs_unknown = QString(_("<b>Techs unknown by you:</b> "));
610 
611  advance_iterate(A_FIRST, padvance)
612  {
613  tech_id = advance_number(padvance);
614  if (research_invention_state(my_research, tech_id) == TECH_KNOWN
615  && (research_invention_state(research, tech_id) != TECH_KNOWN)) {
616  a++;
618  tech_id);
619  }
620  if (research_invention_state(my_research, tech_id) != TECH_KNOWN
621  && (research_invention_state(research, tech_id) == TECH_KNOWN)) {
622  b++;
624  tech_id);
625  }
626  }
628  sorted_list_a.sort(Qt::CaseInsensitive);
629  sorted_list_b.sort(Qt::CaseInsensitive);
630  for (auto const &res : qAsConst(sorted_list_a)) {
631  techs_known = techs_known + QStringLiteral("<i>") + res.toHtmlEscaped()
632  + "," + QStringLiteral("</i>") + sp;
633  }
634  for (auto const &res : qAsConst(sorted_list_b)) {
635  techs_unknown = techs_unknown + QStringLiteral("<i>")
636  + res.toHtmlEscaped() + "," + QStringLiteral("</i>")
637  + sp;
638  }
639  if (a == 0) {
640  techs_known = techs_known + QStringLiteral("<i>") + sp
641  + QString(Q_("?tech:None")) + QStringLiteral("</i>");
642  } else {
643  techs_known.replace(techs_known.lastIndexOf(QLatin1String(",")), 1,
644  QStringLiteral("."));
645  }
646  if (b == 0) {
647  techs_unknown = techs_unknown + QStringLiteral("<i>") + sp
648  + QString(Q_("?tech:None")) + QStringLiteral("</i>");
649  } else {
650  techs_unknown.replace(techs_unknown.lastIndexOf(QLatin1String(",")), 1,
651  QStringLiteral("."));
652  }
654  } else if (global_observer) {
655  tech_str =
656  QString(_("<b>Techs known by %1:</b> "))
657  .arg(QString(nation_plural_for_player(pplayer)).toHtmlEscaped());
658  advance_iterate(A_FIRST, padvance)
659  {
660  tech_id = advance_number(padvance);
661  if (research_invention_state(research, tech_id) == TECH_KNOWN) {
663  tech_id);
664  }
665  }
667  sorted_list_a.sort(Qt::CaseInsensitive);
668  for (auto const &res : qAsConst(sorted_list_a)) {
669  tech_str = tech_str + QStringLiteral("<i>") + res.toHtmlEscaped() + ","
670  + QStringLiteral("</i>") + sp;
671  }
672  }
673  // Wonder information
674  if (BV_ISSET(pplayer->client.visible, NI_WONDERS)) {
675  auto wonders = QStringList();
676  for (int i = 0; i < improvement_count(); ++i) {
677  if (pplayer->wonders[i] == WONDER_NOT_BUILT) {
678  continue;
679  }
680 
681  const auto improve = improvement_by_number(i);
682  const auto name =
683  QString(improvement_name_translation(improve)).toHtmlEscaped();
684  if (pplayer->wonders[i] == WONDER_LOST) {
685  // TRANS: %1 is a wonder name
686  wonders += QString(_("%1 (lost)")).arg(name);
687  } else if (const auto city =
688  game_city_by_number(pplayer->wonders[i])) {
689  // TRANS: %1 is a wonder name, %2 is a city name
690  wonders += QString(_("%1 (in %2)"))
691  .arg(name)
692  .arg(QString(city_name_get(city)).toHtmlEscaped());
693  } else {
694  wonders += name;
695  }
696  }
697  if (!tech_str.isEmpty()) {
698  tech_str += nl;
699  }
700  // TRANS: Followed by a list of wonders the player knows another player
701  // has
702  tech_str += QString(_("<b>Known Wonders: </b>"));
703  if (wonders.isEmpty()) {
704  tech_str += QString(Q_("?wonder:None"));
705  } else {
706  tech_str += strvec_to_and_list(wonders.toVector());
707  }
708  }
709 
710  plr->update_report(false);
711 }
712 
717 
722 {
723  delete pid;
724  delete list_model;
725  delete filter_model;
727  horizontalHeader()->sortIndicatorSection();
729  horizontalHeader()->sortIndicatorOrder();
730 }
731 
736 {
737  ui.setupUi(this);
738 
739  ui.meet_but->setText(_("Meet"));
740  ui.cancel_but->setText(_("Cancel Treaty"));
741  ui.withdraw_but->setText(_("Withdraw Vision"));
742  ui.toggle_ai_but->setText(_("Toggle AI Mode"));
743  ui.diplo_but->setText(_("Active Diplomacy"));
744  ui.diplo_but->setEnabled(false);
745  connect(ui.meet_but, &QAbstractButton::pressed, this,
747  connect(ui.cancel_but, &QAbstractButton::pressed, this,
749  connect(ui.withdraw_but, &QAbstractButton::pressed, this,
751  connect(ui.toggle_ai_but, &QAbstractButton::pressed, this,
753  connect(ui.diplo_but, &QAbstractButton::pressed, this,
755  setLayout(ui.layout);
756  other_player = nullptr;
757  index = 0;
758  if (king()->qt_settings.player_repo_sort_col != -1) {
759  ui.plr_wdg->sortByColumn(king()->qt_settings.player_repo_sort_col,
760  king()->qt_settings.player_report_sort);
761  }
762  const bool has_meeting =
763  (queen()->gimmeIndexOf(QStringLiteral("DDI")) > 0);
764  ui.diplo_but->setEnabled(has_meeting);
765  update_top_bar_diplomacy_status(has_meeting);
767  ui.plr_wdg->set_pr_rep(this);
768 }
769 
773 plr_report::~plr_report() { queen()->removeRepoDlg(QStringLiteral("PLR")); }
774 
779 {
780  queen()->gimmePlace(this, QStringLiteral("PLR"));
781  index = queen()->addGameTab(this);
782  queen()->game_tab_widget->setCurrentIndex(index);
783 }
784 
789 {
790  if (ui.meet_but->isEnabled()) {
791  req_meeeting();
792  }
793 }
794 
799 {
800  dsend_packet_diplomacy_cancel_pact(
801  &client.conn, player_number(other_player), CLAUSE_CEASEFIRE);
802 }
803 
808 {
809  int i;
810  i = queen()->gimmeIndexOf(QStringLiteral("DDI"));
811  if (i < 0) {
812  return;
813  }
814  queen()->game_tab_widget->setCurrentIndex(i);
815 }
816 
821 {
822  dsend_packet_diplomacy_init_meeting_req(&client.conn,
824 }
825 
830 {
831  dsend_packet_diplomacy_cancel_pact(
832  &client.conn, player_number(other_player), CLAUSE_VISION);
833 }
834 
839 {
840  QAction *toggle_ai_act;
841  QAction *ai_level_act;
842  QMenu *ai_menu = new QMenu(this);
843  int level;
844 
845  toggle_ai_act = new QAction(_("Toggle AI Mode"), nullptr);
846  ai_menu->addAction(toggle_ai_act);
847  ai_menu->addSeparator();
848  for (level = 0; level < AI_LEVEL_COUNT; level++) {
849  if (is_settable_ai_level(static_cast<ai_level>(level))) {
850  QString ln = ai_level_translated_name(static_cast<ai_level>(level));
851  ai_level_act = new QAction(ln, nullptr);
852  ai_level_act->setData(QVariant::fromValue(level));
853  ai_menu->addAction(ai_level_act);
854  }
855  }
856  ai_menu->setAttribute(Qt::WA_DeleteOnClose);
857  connect(ai_menu, &QMenu::triggered, [=](QAction *act) {
858  int level;
859  if (act == toggle_ai_act) {
860  send_chat_printf("/aitoggle \"%s\"",
861  player_name(ui.plr_wdg->other_player));
862  return;
863  }
864  if (act && act->isVisible()) {
865  level = act->data().toInt();
866  if (is_human(ui.plr_wdg->other_player)) {
867  send_chat_printf("/aitoggle \"%s\"",
868  player_name(ui.plr_wdg->other_player));
869  }
870  send_chat_printf("/%s %s", ai_level_cmd(static_cast<ai_level>(level)),
871  player_name(ui.plr_wdg->other_player));
872  }
873  });
874 
875  ai_menu->popup(QCursor::pos());
876 }
877 
882 {
883  QModelIndex index = this->indexAt(event->pos());
884  if (index.isValid() && event->button() == Qt::RightButton
886  plr->call_meeting();
887  }
888  QTableView::mousePressEvent(event);
889 }
890 
894 void plr_report::update_report(bool update_selection)
895 {
896  QModelIndex qmi;
897  int player_count = 0;
898 
899  // Force updating selected player information
900  if (update_selection) {
901  qmi = ui.plr_wdg->currentIndex();
902  if (qmi.isValid()) {
903  ui.plr_wdg->clearSelection();
904  ui.plr_wdg->setCurrentIndex(qmi);
905  }
906  }
907 
908  players_iterate(pplayer)
909  {
910  if ((is_barbarian(pplayer))) {
911  continue;
912  }
913  player_count++;
914  }
916 
917  if (player_count != ui.plr_wdg->get_model()->rowCount()) {
918  ui.plr_wdg->get_model()->populate();
919  }
920 
921  auto header = ui.plr_wdg->horizontalHeader();
922  header->resizeSections(QHeaderView::ResizeToContents);
923  header->resizeSection(header->count() - 1, QHeaderView::Stretch);
924 
925  ui.meet_but->setDisabled(true);
926  ui.cancel_but->setDisabled(true);
927  ui.withdraw_but->setDisabled(true);
928  ui.toggle_ai_but->setDisabled(true);
929  ui.plr_label->setText(ui.plr_wdg->intel_str);
930  ui.ally_label->setText(ui.plr_wdg->ally_str);
931  ui.tech_label->setText(ui.plr_wdg->tech_str);
932  other_player = ui.plr_wdg->other_player;
933  if (other_player == nullptr || !can_client_issue_orders()) {
934  return;
935  }
936  if (nullptr != client.conn.playing
938  // We keep button sensitive in case of DIPL_SENATE_BLOCKING, so that
939  // player can request server side to check requirements of those effects
940  // with omniscience
942  != DIPL_ERROR) {
943  ui.cancel_but->setEnabled(true);
944  }
945  ui.toggle_ai_but->setEnabled(true);
946  }
949  ui.withdraw_but->setEnabled(true);
950  }
952  ui.meet_but->setEnabled(true);
953  }
954  const bool has_meeting =
955  (queen()->gimmeIndexOf(QStringLiteral("DDI")) > 0);
956  ui.diplo_but->setEnabled(has_meeting);
957  update_top_bar_diplomacy_status(has_meeting);
958  ui.plr_wdg->restore_selection();
959 }
960 
965 {
966  int i;
967  QWidget *w;
968 
969  if (!queen()->isRepoDlgOpen(QStringLiteral("PLR"))) {
970  plr_report *pr = new plr_report;
971 
972  pr->init();
973  pr->update_report();
974  } else {
975  plr_report *pr;
976 
977  i = queen()->gimmeIndexOf(QStringLiteral("PLR"));
978  w = queen()->game_tab_widget->widget(i);
979  if (w->isVisible()) {
981  return;
982  }
983  pr = reinterpret_cast<plr_report *>(w);
984  queen()->game_tab_widget->setCurrentWidget(pr);
985  pr->update_report();
986  }
988 }
989 
993 void real_players_dialog_update(void *unused)
994 {
995  Q_UNUSED(unused)
996  int i;
997  plr_report *pr;
998  QWidget *w;
999 
1000  if (queen()->isRepoDlgOpen(QStringLiteral("PLR"))) {
1001  i = queen()->gimmeIndexOf(QStringLiteral("PLR"));
1002  if (queen()->game_tab_widget->currentIndex() == i) {
1003  w = queen()->game_tab_widget->widget(i);
1004  pr = reinterpret_cast<plr_report *>(w);
1005  pr->update_report();
1006  }
1007  }
1008 }
1009 
1014 {
1015  int i;
1016  plr_report *pr;
1017  QWidget *w;
1018 
1019  if (queen()->isRepoDlgOpen(QStringLiteral("PLR"))) {
1020  i = queen()->gimmeIndexOf(QStringLiteral("PLR"));
1021  fc_assert(i != -1);
1022  w = queen()->game_tab_widget->widget(i);
1023  pr = reinterpret_cast<plr_report *>(w);
1024  pr->deleteLater();
1025  }
1027 }
1037 
1043 {
1044  queen()->diplomacy_notify = notify;
1047 }
static struct action * actions[MAX_NUM_ACTIONS]
Definition: actions.cpp:91
QString strvec_to_and_list(const QVector< QString > &psv)
Definition: astring.cpp:43
bool BV_ISSET(const BV &bv, int bit)
Definition: bitvector.h:37
int send_chat_printf(const char *format,...)
Send the message as a chat to the server.
const char * city_name_get(const struct city *pcity)
Return the name of the city.
Definition: city.cpp:1077
QFont getFont(const QString &name, double zoom=1.0) const
Returns desired font.
Definition: fonts.cpp:57
static fcFont * instance()
Returns instance of fc_font.
Definition: fonts.cpp:34
fc_settings qt_settings
Definition: fc_client.h:126
A sort and filter proxy model supporting string collation.
void set_collator(const QCollator &coll)
Changes the collator currently in use.
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
bool diplomacy_notify
Definition: page_game.h:89
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
void reloadSidebarIcons()
Reloads top bar icons (useful on theme change)
Definition: page_game.cpp:234
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
Slighty increase deafult cell height.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Paint evenet for custom player item delegation.
bool setData(int column, const QVariant &value, int role=Qt::DisplayRole)
Sets data for plr_item (not used)
QVariant data(int column, int role=Qt::DisplayRole) const
Returns data from item.
struct player * ipplayer
Definition: view_nations.h:63
plr_item(struct player *pplayer)
Constructor for plr_item.
plr_model(QObject *parent=0)
Constructor for player model.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Definition: view_nations.h:81
void populate()
Fills model with data.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::DisplayRole) override
Sets data in model.
QVariant hide_data(int section) const
Returns information about column if hidden.
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Returns header data from model.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Returns data from model.
QList< plr_item * > plr_list
Definition: view_nations.h:98
void notify_plr_changed(int row)
Notifies that row has been changed.
int rowCount(const QModelIndex &index=QModelIndex()) const override
Definition: view_nations.h:76
~plr_model() override
Destructor for player model.
void plr_withdraw_vision()
Slot for withdrawing vision.
Ui::FormPlrDlg ui
Definition: view_nations.h:148
void call_meeting()
Public function to call meeting.
void plr_diplomacy()
Slot for diplomacy.
void update_report(bool update_selection=true)
Updates widget.
void plr_cancel_threaty()
Slot for canceling treaty.
struct player * other_player
Definition: view_nations.h:149
void toggle_ai_mode()
Slot for changing AI mode.
void req_meeeting()
Slot for meeting request.
plr_report()
Constructor for plr_report.
void init()
Adds plr_report to tab widget.
~plr_report() override
Destructor for plr_report.
plr_widget(QWidget *)
Constructor for plr_widget.
void nation_selected(const QItemSelection &sl, const QItemSelection &ds)
Slot for selecting player/nation.
QString techs_known
Definition: view_nations.h:110
struct player * selected_player
Definition: view_nations.h:112
freeciv::collated_sort_filter_proxy_model * filter_model
Definition: view_nations.h:107
~plr_widget() override
Destructor for player widget.
plr_report * plr
Definition: view_nations.h:109
plr_model * list_model
Definition: view_nations.h:106
plr_item_delegate * pid
Definition: view_nations.h:108
void mousePressEvent(QMouseEvent *event) override
Handle mouse click.
QString tech_str
Definition: view_nations.h:122
plr_model * get_model() const
Returns model used in widget.
QString intel_str
Definition: view_nations.h:120
struct player * other_player
Definition: view_nations.h:123
QString ally_str
Definition: view_nations.h:121
QString techs_unknown
Definition: view_nations.h:111
void display_header_menu(const QPoint)
Displays menu on header by right clicking.
void hide_columns()
Hides columns in plr widget, depending on info from plr_list.
void restore_selection()
Restores selection of previously selected nation.
void set_pr_rep(plr_report *pr)
bool can_meet_with_player(const struct player *pplayer)
Returns TRUE iff the client can do diplomatic meetings with another given player.
bool client_is_global_observer()
Returns whether client is global observer.
struct player * client_player()
Either controlling or observing.
struct civclient client
bool can_client_issue_orders()
Returns TRUE iff the client can issue orders (such as giving unit commands).
QColor get_player_color(const struct tileset *t, const struct player *pplayer)
Return the color of the player.
enum event_type event
Definition: events.cpp:68
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
int Tech_type_id
Definition: fc_types.h:294
#define Q_(String)
Definition: fcintl.h:53
#define _(String)
Definition: fcintl.h:50
struct city * game_city_by_number(int id)
Often used function to get a city pointer from a city ID.
Definition: game.cpp:103
const char * government_name_for_player(const struct player *pplayer)
Return the (translated) name of the given government of a player.
Definition: government.cpp:147
const char * ruler_title_for_player(const struct player *pplayer, char *buf, size_t buf_len)
Return the ruler title of the player (translated).
Definition: government.cpp:366
Impr_type_id improvement_count()
Return the number of improvements.
struct impr_type * improvement_by_number(const Impr_type_id id)
Returns the improvement type for the given index/ID.
const char * improvement_name_translation(const struct impr_type *pimprove)
Return the (translated) name of the given improvement.
#define WONDER_NOT_BUILT
Definition: improvement.h:144
#define WONDER_LOST
Definition: improvement.h:143
const char * name
Definition: inputfile.cpp:118
#define fc_assert_ret(condition)
Definition: log.h:112
#define fc_assert(condition)
Definition: log.h:89
const char *const default_font
Definition: fonts.h:18
const char * nation_plural_for_player(const struct player *pplayer)
Return the (translated) plural noun of the given nation of a player.
Definition: nation.cpp:155
const char * nation_adjective_for_player(const struct player *pplayer)
Return the (translated) adjective for the given nation of a player.
Definition: nation.cpp:146
struct nation_type * nation_of_player(const struct player *pplayer)
Return the nation of a player.
Definition: nation.cpp:419
pageGame * queen()
Return game instandce.
Definition: page_game.cpp:557
bool is_settable_ai_level(enum ai_level level)
Return is AI can be set to given level.
Definition: player.cpp:1825
bool players_on_same_team(const struct player *pplayer1, const struct player *pplayer2)
Return TRUE if players are in the same team.
Definition: player.cpp:1405
int player_number(const struct player *pplayer)
Return the player index/number/id.
Definition: player.cpp:756
int player_count()
Return the number of players.
Definition: player.cpp:739
struct city * player_primary_capital(const struct player *pplayer)
Locate the player's primary capital city, (nullptr Otherwise)
Definition: player.cpp:1247
const char * player_name(const struct player *pplayer)
Return the leader name of the player.
Definition: player.cpp:816
enum dipl_reason pplayer_can_cancel_treaty(const struct player *p1, const struct player *p2)
The senate may not allow you to break the treaty.
Definition: player.cpp:90
bool gives_shared_vision(const struct player *me, const struct player *them)
Return TRUE iff the player me gives shared vision to player them.
Definition: player.cpp:1414
struct player_diplstate * player_diplstate_get(const struct player *plr1, const struct player *plr2)
Returns diplomatic state type between two players.
Definition: player.cpp:288
#define ai_level_cmd(_level_)
Definition: player.h:551
#define players_iterate_end
Definition: player.h:520
@ DIPL_ERROR
Definition: player.h:185
#define players_iterate(_pplayer)
Definition: player.h:514
static bool is_barbarian(const struct player *pplayer)
Definition: player.h:474
#define players_iterate_alive_end
Definition: player.h:532
#define is_human(plr)
Definition: player.h:226
#define players_iterate_alive(_pplayer)
Definition: player.h:526
struct research * research_get(const struct player *pplayer)
Returns the research structure associated with the player.
Definition: research.cpp:110
QString research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Store the translated name of the given tech (including A_FUTURE) in 'buf'.
Definition: research.cpp:257
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Returns state of the tech for current research.
Definition: research.cpp:609
struct setting_list * level[OLEVELS_NUM]
Definition: settings.cpp:167
Definition: city.h:291
struct connection conn
Definition: client_main.h:89
struct player * playing
Definition: connection.h:142
Qt::SortOrder player_report_sort
Definition: fc_client.h:62
int player_repo_sort_col
Definition: fc_client.h:57
The base class for options.
Definition: options.cpp:209
enum diplstate_type type
Definition: player.h:193
enum player_dlg_column_type type
Definition: player.h:231
struct player::@65::@68 client
int wonders[B_LAST]
Definition: player.h:283
struct government * government
Definition: player.h:240
bool is_alive
Definition: player.h:250
struct player_economic economic
Definition: player.h:266
Tech_type_id researching
Definition: research.h:45
struct research::@71::@73 client
int bulbs_researched
Definition: research.h:46
Tech_type_id advance_number(const struct advance *padvance)
Return the advance index.
Definition: tech.cpp:85
#define advance_iterate(_start, _p)
Definition: tech.h:232
#define A_FIRST
Definition: tech.h:37
#define A_UNSET
Definition: tech.h:41
#define advance_iterate_end
Definition: tech.h:238
#define A_UNKNOWN
Definition: tech.h:42
const QPixmap * get_nation_flag_sprite(const struct tileset *t, const struct nation_type *pnation)
Return the sprite for the nation.
Definition: tilespec.cpp:3367
const QPixmap * get_government_sprite(const struct tileset *t, const struct government *gov)
Return the sprite for the government.
Definition: tilespec.cpp:3404
void top_bar_show_map()
Callback to show map.
Definition: top_bar.cpp:448
void update_top_bar_diplomacy_status(bool notify)
Function to update the top bar button.
void popdown_players_report()
Closes players report.
void close_intel_dialog(struct player *p)
Close an intelligence dialog for the given player.
void real_players_dialog_update(void *unused)
Update all information in the player list dialog.
static QRect check_box_rect(const QStyleOptionViewItem &view_item_style_options)
Help function to draw checkbox inside delegate.
void popup_players_dialog()
Display the player list dialog.
void update_intel_dialog(struct player *p)
Update the intelligence dialog for the given player.
struct player_dlg_column player_dlg_columns[]
...
const int num_player_dlg_columns
@ COL_TEXT
@ COL_BOOLEAN
@ COL_FLAG
@ COL_RIGHT_TEXT
@ COL_COLOR
@ COL_GOVERNMENT
static void improve(struct reqtree *tree)
Try to reduce the number of crossings by swapping two nodes and checking if it improves the situation...