1 //  Copyright (C) 2007-2009, 2011, 2012, 2014-2017, 2020 Ben Asselstine
2 //
3 //  This program is free software; you can redistribute it and/or modify
4 //  it under the terms of the GNU General Public License as published by
5 //  the Free Software Foundation; either version 3 of the License, or
6 //  (at your option) any later version.
7 //
8 //  This program is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //  GNU Library General Public License for more details.
12 //
13 //  You should have received a copy of the GNU General Public License
14 //  along with this program; if not, write to the Free Software
15 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 //  02110-1301, USA.
17 
18 #include <config.h>
19 
20 #include <gtkmm.h>
21 #include <sigc++/functors/mem_fun.h>
22 
23 #include "report-dialog.h"
24 #include "bar-chart.h"
25 #include "ucompose.hpp"
26 #include "defs.h"
27 #include "GameMap.h"
28 #include "playerlist.h"
29 #include "citylist.h"
30 #include "city.h"
31 #include "action.h"
32 #include "ImageCache.h"
33 #include "armysetlist.h"
34 #include "shield.h"
35 #include "armyprodbase.h"
36 #include "font-size.h"
37 
38 #define method(x) sigc::mem_fun(*this, &ReportDialog::x)
39 
ReportDialog(Gtk::Window & parent,Player * player,ReportType type)40 ReportDialog::ReportDialog(Gtk::Window &parent, Player *player, ReportType type)
41  : LwDialog(parent, "report-dialog.ui")
42 {
43   d_player = player;
44   xml->get_widget("map_image", map_image);
45   citymap = new CityMap();
46   citymap->map_changed.connect (method(on_city_map_changed));
47   armymap = new ArmyMap();
48   armymap->map_changed.connect (method(on_army_map_changed));
49   City *c = d_player->getFirstCity();
50   vectormap = new VectorMap(c, VectorMap::SHOW_ALL_VECTORING, false);
51   vectormap->map_changed.connect (method(on_vector_map_changed));
52 
53   xml->get_widget("army_label", army_label);
54   xml->get_widget("city_label", city_label);
55   xml->get_widget("gold_label", gold_label);
56   xml->get_widget("production_label", production_label);
57   xml->get_widget("winning_label", winning_label);
58 
59 
60   xml->get_widget("report_notebook", report_notebook);
61   report_notebook->set_current_page(type);
62   switch_conn = report_notebook->signal_switch_page().connect
63     (sigc::hide<0>(method(on_switch_page)));
64 
65   armies_list = Gtk::ListStore::create(armies_columns);
66   xml->get_widget("treeview", armies_treeview);
67   armies_treeview->set_model(armies_list);
68   armies_treeview->append_column("", armies_columns.image);
69   armies_treeview->append_column("", armies_columns.desc);
70 
71   //loop through the action list looking for production actions
72   std::list<Action*> actions = player->getReportableActions();
73   guint32 total = 0;
74   std::list<Action*>::const_iterator it;
75   for (it = actions.begin(); it != actions.end(); it++)
76     {
77       if ((*it)->getType() == Action::PRODUCE_UNIT ||
78 	  (*it)->getType() == Action::PRODUCE_VECTORED_UNIT)
79 	total++;
80     addProduction(*it);
81     }
82     armies_treeview->get_selection()->signal_changed().connect
83       (method(on_army_selected));
84 
85   Glib::ustring s;
86   s = String::ucompose(ngettext("You produced %1 army this turn!",
87 				"You produced %1 armies this turn!",
88 		  		total), total);
89   production_label->set_text(s);
90 
91   xml->get_widget("army_alignment", army_alignment);
92   xml->get_widget("city_alignment", city_alignment);
93   xml->get_widget("gold_alignment", gold_alignment);
94   xml->get_widget("winning_alignment", winning_alignment);
95   updateArmyChart();
96   updateGoldChart();
97   updateCityChart();
98   updateWinningChart();
99   fill_in_info();
100 }
101 
~ReportDialog()102 ReportDialog::~ReportDialog()
103 {
104   switch_conn.disconnect();
105   delete vectormap;
106   delete armymap;
107   delete citymap;
108   report_notebook->property_show_tabs () = false;
109 }
110 
run()111 void ReportDialog::run()
112 {
113   citymap->resize();
114   citymap->draw();
115   vectormap->resize();
116   vectormap->draw();
117   armymap->resize();
118   armymap->draw();
119 
120   dialog->show_all();
121   dialog->run();
122 }
123 
on_army_map_changed(Cairo::RefPtr<Cairo::Surface> map)124 void ReportDialog::on_army_map_changed(Cairo::RefPtr<Cairo::Surface> map)
125 {
126   if (report_notebook->get_current_page() == ARMY)
127     {
128       Glib::RefPtr<Gdk::Pixbuf> pixbuf =
129         Gdk::Pixbuf::create(map, 0, 0,
130                             armymap->get_width(), armymap->get_height());
131       map_image->property_pixbuf() = pixbuf;
132     }
133 }
134 
on_city_map_changed(Cairo::RefPtr<Cairo::Surface> map)135 void ReportDialog::on_city_map_changed(Cairo::RefPtr<Cairo::Surface> map)
136 {
137   if (report_notebook->get_current_page() == CITY ||
138       report_notebook->get_current_page() == GOLD ||
139       report_notebook->get_current_page() == WINNING)
140     {
141       Glib::RefPtr<Gdk::Pixbuf> pixbuf =
142         Gdk::Pixbuf::create(map, 0, 0,
143                             citymap->get_width(), citymap->get_height());
144       map_image->property_pixbuf() = pixbuf;
145     }
146 }
147 
on_vector_map_changed(Cairo::RefPtr<Cairo::Surface> map)148 void ReportDialog::on_vector_map_changed(Cairo::RefPtr<Cairo::Surface> map)
149 {
150   if (report_notebook->get_current_page() == PRODUCTION)
151     {
152       Glib::RefPtr<Gdk::Pixbuf> pixbuf =
153         Gdk::Pixbuf::create(map, 0, 0,
154                             vectormap->get_width(), vectormap->get_height());
155       map_image->property_pixbuf() = pixbuf;
156     }
157 }
158 
on_switch_page(guint number)159 void ReportDialog::on_switch_page(guint number)
160 {
161   switch (number)
162     {
163     case ARMY:
164       map_image->property_pixbuf() =
165         Gdk::Pixbuf::create(armymap->get_surface(), 0, 0,
166                             armymap->get_width(), citymap->get_height());
167       break;
168     case CITY:
169     case GOLD:
170     case WINNING:
171       map_image->property_pixbuf() =
172         Gdk::Pixbuf::create(citymap->get_surface(), 0, 0,
173                             citymap->get_width(), citymap->get_height());
174       break;
175     case PRODUCTION:
176       map_image->property_pixbuf() =
177         Gdk::Pixbuf::create(vectormap->get_surface(), 0, 0,
178                             vectormap->get_width(), vectormap->get_height());
179       break;
180     }
181   fill_in_info();
182 }
183 
fill_in_info()184 void ReportDialog::fill_in_info()
185 {
186   switch (report_notebook->get_current_page())
187     {
188     case ARMY:
189       dialog->set_title(_("Army Report"));
190       break;
191     case CITY:
192       dialog->set_title(_("City Report"));
193       break;
194     case GOLD:
195       dialog->set_title(_("Gold Report"));
196       break;
197     case PRODUCTION:
198       dialog->set_title(_("Production Report"));
199       break;
200     case WINNING:
201       dialog->set_title(_("Winning Report"));
202       break;
203     }
204 }
205 
updateArmyChart()206 void ReportDialog::updateArmyChart()
207 {
208   std::list<guint32> bars;
209   std::list<Gdk::RGBA> colours;
210   Gdk::RGBA colour;
211   Glib::ustring s;
212   guint32 total;
213   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
214     {
215       Player *p = Playerlist::getInstance()->getPlayer(i);
216       if (p == NULL)
217 	continue;
218       if (p == Playerlist::getInstance()->getNeutral())
219 	continue;
220       total = 0;
221       total = p->countArmies();
222       bars.push_back(total);
223       colour = p->getColor();
224       colours.push_back(colour);
225       if (p == d_player)
226         army_label->set_text
227           (String::ucompose(ngettext("You have %1 army!", "You have %1 armies!",
228                                      total), total));
229     }
230 
231   army_chart = new BarChart(bars, colours, 0);
232   army_alignment->add(*manage(army_chart));
233 }
234 
updateCityChart()235 void ReportDialog::updateCityChart()
236 {
237   std::list<guint32> bars;
238   std::list<Gdk::RGBA> colours;
239   Gdk::RGBA colour;
240   Glib::ustring s;
241   guint32 total;
242   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
243     {
244       Player *p = Playerlist::getInstance()->getPlayer(i);
245       if (p == NULL)
246 	continue;
247       if (p == Playerlist::getInstance()->getNeutral())
248 	continue;
249       total = Citylist::getInstance()->countCities(p);
250 
251       bars.push_back(total);
252       colour = p->getColor();
253       colours.push_back(colour);
254       if (p == d_player)
255         city_label->set_text
256           (String::ucompose(ngettext("You have %1 city!", "You have %1 cities!",
257                                      total), total));
258 
259     }
260   city_chart = new BarChart(bars, colours, Citylist::getInstance()->size());
261   city_alignment->add(*manage(city_chart));
262 }
263 
updateGoldChart()264 void ReportDialog::updateGoldChart()
265 {
266   std::list<guint32> bars;
267   std::list<Gdk::RGBA> colours;
268   Gdk::RGBA colour;
269   Glib::ustring s;
270   guint32 total;
271   bars.clear();
272   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
273     {
274       Player *p = Playerlist::getInstance()->getPlayer(i);
275       if (p == NULL)
276 	continue;
277       if (p == Playerlist::getInstance()->getNeutral())
278 	continue;
279       total = p->getGold();
280       bars.push_back(total);
281       colour = p->getColor();
282       colours.push_back(colour);
283       if (p == d_player)
284         gold_label->set_text
285           (String::ucompose(ngettext("You have %1 gold piece!",
286                                      "You have %1 gold pieces!", total), total));
287     }
288   gold_chart = new BarChart(bars, colours, 0);
289   gold_alignment->add(*manage(gold_chart));
290 }
291 
get_rank_string(int rank)292 Glib::ustring ReportDialog::get_rank_string(int rank)
293 {
294   if (rank == 0)
295       return _("first");
296   else if (rank == 1)
297     return _("second");
298   else if (rank == 2)
299     return _("third");
300   else if (rank == 3)
301     return _("fourth");
302   else if (rank == 4)
303     return _("fifth");
304   else if (rank == 5)
305     return _("sixth");
306   else if (rank == 6)
307     return _("seventh");
308   else if (rank == 7)
309     return _("eighth");
310   else
311     return _("unknown");
312 }
313 
calculateRank(std::list<guint32> scores,guint32 score)314 Glib::ustring ReportDialog::calculateRank(std::list<guint32> scores, guint32 score)
315 {
316   guint32 rank = 0;
317   std::list<guint32>::iterator it = scores.begin();
318   for (; it != scores.end(); it++)
319     {
320       if (score < *it)
321 	rank++;
322     }
323   Glib::ustring s = String::ucompose("%1", get_rank_string(rank));
324   return s;
325 }
326 
updateWinningChart()327 void ReportDialog::updateWinningChart()
328 {
329   std::list<guint32> bars;
330   std::list<Gdk::RGBA> colours;
331   Gdk::RGBA colour;
332   Glib::ustring s;
333   guint32 score;
334   for (unsigned int i = 0; i < MAX_PLAYERS; i++)
335     {
336       Player *p = Playerlist::getInstance()->getPlayer(i);
337       if (p == NULL)
338 	continue;
339       if (p == Playerlist::getInstance()->getNeutral())
340 	continue;
341       score = p->getScore();
342       bars.push_back(score);
343       colour = p->getColor();
344       colours.push_back(colour);
345     }
346   s = String::ucompose(_("You are coming %1"), calculateRank(bars, d_player->getScore()));
347   winning_label->set_text(s);
348   winning_chart = new BarChart(bars, colours, 100);
349   winning_alignment->add(*manage(winning_chart));
350 }
351 
addProduction(const Action * action)352 void ReportDialog::addProduction(const Action *action)
353 {
354   ImageCache *gc = ImageCache::getInstance();
355   Player *p = d_player;
356 
357   int army_type = 0;
358   guint32 city_id = 0;
359 
360   Glib::ustring s = "";
361   if (action->getType() == Action::PRODUCE_UNIT)
362     {
363       const Action_Produce *act;
364       act = dynamic_cast<const Action_Produce*>(action);
365       army_type = act->getArmy()->getTypeId();
366       Citylist::iterator cit = Citylist::getInstance()->begin();
367       for (; cit != Citylist::getInstance()->end(); ++cit)
368 	if ((*cit)->getId() == act->getCityId())
369 	  {
370 	    s += (*cit)->getName();
371 	    break;
372 	  }
373       if (act->getVectored())
374 	s += "...";
375       city_id = act->getCityId();
376     }
377   else if (action->getType() == Action::PRODUCE_VECTORED_UNIT)
378     {
379       const Action_ProduceVectored *act =
380         dynamic_cast<const Action_ProduceVectored*>(action);
381       army_type = act->getArmy()->getTypeId();
382       Vector<int> pos = act->getDestination();
383       City *c = GameMap::getCity(pos);
384       s+="...";
385       if (c)
386 	s += c->getName();
387       else
388 	s += _("Standard");
389       city_id = GameMap::getCity(act->getOrigination())->getId();
390     }
391   else if (action->getType() == Action::CITY_DESTITUTE)
392     {
393       const Action_CityTooPoorToProduce *act;
394       act = dynamic_cast<const Action_CityTooPoorToProduce*>(action);
395       army_type = act->getArmyType();
396       City *c = Citylist::getInstance()->getById(act->getCityId());
397       s = String::ucompose(_("%1 stops production!"), c->getName());
398       city_id = act->getCityId();
399     }
400   Gtk::TreeIter i = armies_list->append();
401   (*i)[armies_columns.city_id] = city_id;
402   (*i)[armies_columns.image] =
403     gc->getCircledArmyPic(p->getArmyset(), army_type, p, NULL, false,
404                           Shield::NEUTRAL, true,
405                           FontSize::getInstance ()->get_height ())->to_pixbuf();
406   (*i)[armies_columns.desc] = s;
407 }
408 
on_army_selected()409 void ReportDialog::on_army_selected()
410 {
411     Gtk::TreeIter i = armies_treeview->get_selection()->get_selected();
412     if (i)
413     {
414 	City *c =
415 	  Citylist::getInstance()->getById((*i)[armies_columns.city_id]);
416 	if (c)
417 	  vectormap->setCity(c);
418     }
419 }
420