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