1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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 2, or (at your option)
6    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 General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 
21 #include <gtk/gtk.h>
22 
23 /* utility */
24 #include "fcintl.h"
25 #include "log.h"
26 #include "shared.h"
27 #include "support.h"
28 
29 /* common */
30 #include "government.h"
31 #include "packets.h"
32 #include "player.h"
33 #include "research.h"
34 
35 /* client */
36 #include "client_main.h"
37 #include "options.h"
38 
39 /* client/gui-gtk-3.22 */
40 #include "gui_main.h"
41 #include "gui_stuff.h"
42 #include "mapview.h"
43 
44 #include "inteldlg.h"
45 
46 /******************************************************************/
47 static const char *table_text[] = {
48   N_("Ruler:"),
49   N_("Government:"),
50   N_("Capital:"),
51   N_("Gold:"),
52   NULL,
53   N_("Tax:"),
54   N_("Science:"),
55   N_("Luxury:"),
56   NULL,
57   N_("Researching:")
58 };
59 
60 enum table_label {
61   LABEL_RULER,
62   LABEL_GOVERNMENT,
63   LABEL_CAPITAL,
64   LABEL_GOLD,
65   LABEL_SEP1,
66   LABEL_TAX,
67   LABEL_SCIENCE,
68   LABEL_LUXURY,
69   LABEL_SEP2,
70   LABEL_RESEARCHING,
71   LABEL_LAST
72 };
73 
74 /******************************************************************/
75 struct intel_dialog {
76   struct player *pplayer;
77   GtkWidget *shell;
78 
79   GtkTreeStore *diplstates;
80   GtkListStore *techs;
81   GtkWidget *table_labels[LABEL_LAST];
82 };
83 
84 #define SPECLIST_TAG dialog
85 #define SPECLIST_TYPE struct intel_dialog
86 #include "speclist.h"
87 
88 #define dialog_list_iterate(dialoglist, pdialog) \
89     TYPED_LIST_ITERATE(struct intel_dialog, dialoglist, pdialog)
90 #define dialog_list_iterate_end  LIST_ITERATE_END
91 
92 static struct dialog_list *dialog_list;
93 static struct intel_dialog *create_intel_dialog(struct player *p);
94 
95 /****************************************************************
96   Initialize intelligenze dialogs
97 *****************************************************************/
intel_dialog_init(void)98 void intel_dialog_init(void)
99 {
100   dialog_list = dialog_list_new();
101 }
102 
103 /****************************************************************
104   Free resources allocated for intelligenze dialogs
105 *****************************************************************/
intel_dialog_done(void)106 void intel_dialog_done(void)
107 {
108   dialog_list_destroy(dialog_list);
109 }
110 
111 /****************************************************************
112   Get intelligenze dialog between client user and other player
113   passed as parameter.
114 *****************************************************************/
get_intel_dialog(struct player * pplayer)115 static struct intel_dialog *get_intel_dialog(struct player *pplayer)
116 {
117   dialog_list_iterate(dialog_list, pdialog) {
118     if (pdialog->pplayer == pplayer) {
119       return pdialog;
120     }
121   } dialog_list_iterate_end;
122 
123   return NULL;
124 }
125 
126 /****************************************************************
127   Open intelligenze dialog
128 *****************************************************************/
popup_intel_dialog(struct player * p)129 void popup_intel_dialog(struct player *p)
130 {
131   struct intel_dialog *pdialog;
132 
133   if (!(pdialog = get_intel_dialog(p))) {
134     pdialog = create_intel_dialog(p);
135   }
136 
137   update_intel_dialog(p);
138 
139   gtk_window_present(GTK_WINDOW(pdialog->shell));
140 }
141 
142 /****************************************************************
143   Intelligenze dialog destruction requested
144 *****************************************************************/
intel_destroy_callback(GtkWidget * w,gpointer data)145 static void intel_destroy_callback(GtkWidget *w, gpointer data)
146 {
147   struct intel_dialog *pdialog = (struct intel_dialog *)data;
148 
149   dialog_list_remove(dialog_list, pdialog);
150 
151   free(pdialog);
152 }
153 
154 /**************************************************************************
155   Close an intelligence dialog for the given player.
156 **************************************************************************/
close_intel_dialog(struct player * p)157 void close_intel_dialog(struct player *p)
158 {
159   struct intel_dialog *pdialog = get_intel_dialog(p);
160   intel_destroy_callback(NULL, pdialog);
161 }
162 
163 /****************************************************************
164   Create new intelligenze dialog between client user and player
165   given as parameter.
166 *****************************************************************/
create_intel_dialog(struct player * p)167 static struct intel_dialog *create_intel_dialog(struct player *p)
168 {
169   struct intel_dialog *pdialog;
170 
171   GtkWidget *shell, *notebook, *label, *sw, *view, *table;
172   GtkCellRenderer *rend;
173   GtkTreeViewColumn *col;
174   int i;
175 
176   pdialog = fc_malloc(sizeof(*pdialog));
177   pdialog->pplayer = p;
178 
179   shell = gtk_dialog_new_with_buttons(NULL,
180                                       NULL,
181                                       0,
182                                       _("_Close"),
183                                       GTK_RESPONSE_CLOSE,
184                                       NULL);
185   pdialog->shell = shell;
186   gtk_window_set_default_size(GTK_WINDOW(shell), 350, 350);
187   setup_dialog(shell, toplevel);
188   gtk_dialog_set_default_response(GTK_DIALOG(shell), GTK_RESPONSE_CLOSE);
189 
190   g_signal_connect(shell, "destroy",
191                    G_CALLBACK(intel_destroy_callback), pdialog);
192   g_signal_connect(shell, "response",
193                    G_CALLBACK(gtk_widget_destroy), NULL);
194 
195   notebook = gtk_notebook_new();
196   gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
197   gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), notebook);
198 
199   /* overview tab. */
200   table = gtk_grid_new();
201   g_object_set(table, "margin", 6, NULL);
202 
203   gtk_grid_set_row_spacing(GTK_GRID(table), 2);
204   gtk_grid_set_column_spacing(GTK_GRID(table), 12);
205 
206   /* TRANS: Overview tab of foreign intelligence report dialog */
207   label = gtk_label_new_with_mnemonic(_("_Overview"));
208   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), table, label);
209 
210   for (i = 0; i < ARRAY_SIZE(table_text); i++) {
211     if (table_text[i]) {
212       label = gtk_label_new(_(table_text[i]));
213       gtk_widget_set_halign(label, GTK_ALIGN_START);
214       gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
215       gtk_grid_attach(GTK_GRID(table), label, 0, i, 1, 1);
216 
217       label = gtk_label_new(NULL);
218       pdialog->table_labels[i] = label;
219       gtk_widget_set_halign(label, GTK_ALIGN_START);
220       gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
221       gtk_grid_attach(GTK_GRID(table), label, 1, i, 1, 1);
222     } else {
223       pdialog->table_labels[i] = NULL;
224     }
225   }
226 
227   /* diplomacy tab. */
228   pdialog->diplstates = gtk_tree_store_new(1, G_TYPE_STRING);
229 
230   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pdialog->diplstates));
231   g_object_set(view, "margin", 6, NULL);
232   gtk_widget_set_hexpand(view, TRUE);
233   gtk_widget_set_vexpand(view, TRUE);
234   g_object_unref(pdialog->diplstates);
235   gtk_container_set_border_width(GTK_CONTAINER(view), 6);
236   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
237 
238   rend = gtk_cell_renderer_text_new();
239   col = gtk_tree_view_column_new_with_attributes(NULL, rend,
240     "text", 0, NULL);
241   gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
242 
243   gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
244 
245   sw = gtk_scrolled_window_new(NULL,NULL);
246   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
247 				      GTK_SHADOW_ETCHED_IN);
248   gtk_container_add(GTK_CONTAINER(sw), view);
249 
250   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
251 	GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
252 
253   label = gtk_label_new_with_mnemonic(_("_Diplomacy"));
254   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, label);
255 
256   /* techs tab. */
257   pdialog->techs = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING);
258   gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(pdialog->techs),
259       1, GTK_SORT_ASCENDING);
260 
261   view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pdialog->techs));
262   g_object_set(view, "margin", 6, NULL);
263   gtk_widget_set_hexpand(view, TRUE);
264   gtk_widget_set_vexpand(view, TRUE);
265   g_object_unref(pdialog->techs);
266   gtk_container_set_border_width(GTK_CONTAINER(view), 6);
267   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
268 
269   rend = gtk_cell_renderer_toggle_new();
270   col = gtk_tree_view_column_new_with_attributes(NULL, rend,
271     "active", 0, NULL);
272   gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
273 
274   rend = gtk_cell_renderer_text_new();
275   col = gtk_tree_view_column_new_with_attributes(NULL, rend,
276     "text", 1, NULL);
277   gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
278 
279   sw = gtk_scrolled_window_new(NULL,NULL);
280   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
281 				      GTK_SHADOW_ETCHED_IN);
282   gtk_container_add(GTK_CONTAINER(sw), view);
283 
284   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
285 	GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
286 
287   label = gtk_label_new_with_mnemonic(_("_Techs"));
288   gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, label);
289 
290   gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(shell)));
291 
292   dialog_list_prepend(dialog_list, pdialog);
293 
294   return pdialog;
295 }
296 
297 /****************************************************************************
298   Update the intelligence dialog for the given player. This is called by
299   the core client code when that player's information changes.
300 ****************************************************************************/
update_intel_dialog(struct player * p)301 void update_intel_dialog(struct player *p)
302 {
303   struct intel_dialog *pdialog = get_intel_dialog(p);
304 
305   if (pdialog) {
306     const struct research *mresearch, *presearch;
307     GtkTreeIter diplstates[DS_LAST];
308     int i;
309     bool global_observer = client_is_global_observer();
310     struct player *me = client_player();
311     bool embassy_knowledge = global_observer || player_has_embassy(me, p);
312     bool trade_knowledge = global_observer || p == me || could_intel_with_player(me, p);
313 
314     /* window title. */
315     gchar *title = g_strdup_printf(_("Foreign Intelligence: %s Empire"),
316 			  nation_adjective_for_player(p));
317     gtk_window_set_title(GTK_WINDOW(pdialog->shell), title);
318     g_free(title);
319 
320     /* diplomacy tab. */
321     gtk_tree_store_clear(pdialog->diplstates);
322 
323     for (i = 0; i < ARRAY_SIZE(diplstates); i++) {
324       GtkTreeIter it;
325       GValue v = { 0, };
326 
327       gtk_tree_store_append(pdialog->diplstates, &it, NULL);
328       g_value_init(&v, G_TYPE_STRING);
329       g_value_set_static_string(&v, diplstate_type_translated_name(i));
330       gtk_tree_store_set_value(pdialog->diplstates, &it, 0, &v);
331       g_value_unset(&v);
332       diplstates[i] = it;
333     }
334 
335     players_iterate(other) {
336       const struct player_diplstate *state;
337       GtkTreeIter it;
338       GValue v = { 0, };
339 
340       if (other == p || !other->is_alive) {
341 	continue;
342       }
343       state = player_diplstate_get(p, other);
344       gtk_tree_store_append(pdialog->diplstates, &it,
345 			    &diplstates[state->type]);
346       g_value_init(&v, G_TYPE_STRING);
347       g_value_set_static_string(&v, player_name(other));
348       gtk_tree_store_set_value(pdialog->diplstates, &it, 0, &v);
349       g_value_unset(&v);
350     } players_iterate_end;
351 
352     /* techs tab. */
353     gtk_list_store_clear(pdialog->techs);
354 
355     mresearch = research_get(client_player());
356     presearch = research_get(p);
357     advance_index_iterate(A_FIRST, advi) {
358       if (research_invention_state(presearch, advi) == TECH_KNOWN) {
359         GtkTreeIter it;
360 
361         gtk_list_store_append(pdialog->techs, &it);
362 
363         gtk_list_store_set(pdialog->techs, &it,
364                            0, research_invention_state(mresearch, advi)
365                            != TECH_KNOWN,
366                            1, research_advance_name_translation(presearch,
367                                                                 advi),
368                            -1);
369       }
370     } advance_index_iterate_end;
371 
372     /* table labels. */
373     for (i = 0; i < ARRAY_SIZE(pdialog->table_labels); i++) {
374       if (pdialog->table_labels[i]) {
375         struct city *pcity;
376         gchar *buf = NULL;
377         char tbuf[256];
378 
379         switch (i) {
380         case LABEL_RULER:
381           ruler_title_for_player(p, tbuf, sizeof(tbuf));
382           buf = g_strdup(tbuf);
383           break;
384         case LABEL_GOVERNMENT:
385           if (trade_knowledge) {
386             buf = g_strdup(government_name_for_player(p));
387           } else {
388             buf = g_strdup(_("(Unknown)"));
389           }
390           break;
391         case LABEL_CAPITAL:
392           pcity = player_capital(p);
393           /* TRANS: "unknown" location */
394           buf = g_strdup((!pcity) ? _("(Unknown)") : city_name_get(pcity));
395           break;
396         case LABEL_GOLD:
397           if (trade_knowledge) {
398             buf = g_strdup_printf("%d", p->economic.gold);
399           } else {
400             buf = g_strdup(_("(Unknown)"));
401           }
402           break;
403         case LABEL_TAX:
404           if (embassy_knowledge) {
405             buf = g_strdup_printf("%d%%", p->economic.tax);
406           } else {
407             buf = g_strdup(_("(Unknown)"));
408           }
409           break;
410         case LABEL_SCIENCE:
411           if (embassy_knowledge) {
412             buf = g_strdup_printf("%d%%", p->economic.science);
413           } else {
414             buf = g_strdup(_("(Unknown)"));
415           }
416           break;
417         case LABEL_LUXURY:
418           if (embassy_knowledge) {
419             buf = g_strdup_printf("%d%%", p->economic.luxury);
420           } else {
421             buf = g_strdup(_("(Unknown)"));
422           }
423           break;
424         case LABEL_RESEARCHING:
425           {
426             struct research *research = research_get(p);
427 
428             switch (research->researching) {
429             case A_UNKNOWN:
430               /* TRANS: "Unknown" advance/technology */
431               buf = g_strdup(_("(Unknown)"));
432               break;
433             case A_UNSET:
434               if (embassy_knowledge) {
435                 /* TRANS: missing value */
436                 buf = g_strdup(_("(none)"));
437               } else {
438                 buf = g_strdup(_("(Unknown)"));
439               }
440               break;
441             default:
442               buf = g_strdup_printf("%s(%d/%d)",
443                                     research_advance_name_translation
444                                         (research, research->researching),
445                                     research->bulbs_researched,
446                                     research->client.researching_cost);
447               break;
448             }
449             break;
450           }
451         default:
452           break;
453         }
454 
455         if (buf) {
456           gtk_label_set_text(GTK_LABEL(pdialog->table_labels[i]), buf);
457 	  g_free(buf);
458         }
459       }
460     }
461   }
462 }
463