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 #include <string.h>
21
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24
25 /* utility */
26 #include "fcintl.h"
27 #include "log.h"
28 #include "shared.h"
29 #include "support.h"
30
31 /* common */
32 #include "city.h"
33 #include "game.h"
34 #include "packets.h"
35 #include "unit.h"
36
37 /* client/agents */
38 #include "cma_fec.h"
39
40 /* client */
41 #include "citydlg_common.h"
42 #include "cityrepdata.h"
43 #include "client_main.h"
44 #include "climisc.h"
45 #include "global_worklist.h"
46 #include "mapview_common.h"
47 #include "options.h"
48
49 /* gui-gtk-2.0 */
50 #include "chatline.h"
51 #include "citydlg.h"
52 #include "gui_main.h"
53 #include "gui_stuff.h"
54 #include "mapview.h"
55 #include "mapctrl.h" /* is_city_hilited() */
56 #include "optiondlg.h"
57 #include "repodlgs.h"
58
59 #include "cityrep.h"
60
61 #define NEG_VAL(x) ((x)<0 ? (x) : (-x))
62
63 /* Some versions of gcc have problems with negative values here (PR#39722). */
64 #define CMA_NONE (10000)
65 #define CMA_CUSTOM (10001)
66
67 struct sell_data {
68 int count; /* Number of cities. */
69 int gold; /* Amount of gold. */
70 struct impr_type *target; /* The target for selling. */
71 };
72
73 enum city_operation_type {
74 CO_CHANGE, CO_LAST, CO_NEXT, CO_FIRST, CO_NEXT_TO_LAST, CO_SELL, CO_NONE
75 };
76
77 /******************************************************************/
78 static void create_city_report_dialog(bool make_modal);
79
80 static void city_activated_callback(GtkTreeView *view, GtkTreePath *path,
81 GtkTreeViewColumn *col, gpointer data);
82
83 static void city_command_callback(struct gui_dialog *dlg, int response,
84 gpointer data);
85
86 static void city_selection_changed_callback(GtkTreeSelection *selection);
87 static void city_clear_worklist_callback(GtkMenuItem *item, gpointer data);
88 static void update_total_buy_cost(void);
89
90 static void create_select_menu(GtkWidget *item);
91 static void create_change_menu(GtkWidget *item);
92 static void create_last_menu(GtkWidget *item);
93 static void create_first_menu(GtkWidget *item);
94 static void create_next_menu(GtkWidget *item);
95 static void create_next_to_last_menu(GtkWidget *item);
96 static void create_sell_menu(GtkWidget *item);
97
98 static struct gui_dialog *city_dialog_shell = NULL;
99
100 enum {
101 CITY_CENTER = 1, CITY_POPUP, CITY_BUY
102 };
103
104 static GtkWidget *city_view;
105 static GtkTreeSelection *city_selection;
106 static GtkListStore *city_model;
107 #define CRD_COL_CITY_ID (0 + NUM_CREPORT_COLS)
108
109 static void popup_select_menu(GtkMenuShell *menu, gpointer data);
110 static void popup_change_menu(GtkMenuShell *menu, gpointer data);
111 static void popup_last_menu(GtkMenuShell *menu, gpointer data);
112 static void popup_first_menu(GtkMenuShell *menu, gpointer data);
113 static void popup_next_menu(GtkMenuShell *menu, gpointer data);
114 static void popup_next_to_last_menu(GtkMenuShell *menu, gpointer data);
115
116 static void recreate_sell_menu(void);
117
118 static GtkWidget *city_center_command;
119 static GtkWidget *city_popup_command;
120 static GtkWidget *city_buy_command;
121 static GtkWidget *city_production_command;
122 static GtkWidget *city_governor_command;
123 static GtkWidget *city_sell_command;
124 static GtkWidget *city_total_buy_cost_label;
125
126 static GtkWidget *change_improvements_item;
127 static GtkWidget *change_units_item;
128 static GtkWidget *change_wonders_item;
129
130 static GtkWidget *last_improvements_item;
131 static GtkWidget *last_units_item;
132 static GtkWidget *last_wonders_item;
133
134 static GtkWidget *first_improvements_item;
135 static GtkWidget *first_units_item;
136 static GtkWidget *first_wonders_item;
137
138 static GtkWidget *next_improvements_item;
139 static GtkWidget *next_units_item;
140 static GtkWidget *next_wonders_item;
141
142 static GtkWidget *next_to_last_improvements_item;
143 static GtkWidget *next_to_last_units_item;
144 static GtkWidget *next_to_last_wonders_item;
145
146 static GtkWidget *select_island_item;
147
148 static GtkWidget *select_bunit_item;
149 static GtkWidget *select_bimprovement_item;
150 static GtkWidget *select_bwonder_item;
151
152 static GtkWidget *select_supported_item;
153 static GtkWidget *select_present_item;
154 static GtkWidget *select_built_improvements_item;
155 static GtkWidget *select_built_wonders_item;
156
157 static GtkWidget *select_improvements_item;
158 static GtkWidget *select_units_item;
159 static GtkWidget *select_wonders_item;
160 static GtkWidget *select_cma_item;
161
162 static int city_dialog_shell_is_modal;
163
164 bool select_menu_cached;
165
166 /****************************************************************
167 Return text line for the column headers for the city report
168 *****************************************************************/
get_city_table_header(char ** text,int n)169 static void get_city_table_header(char **text, int n)
170 {
171 struct city_report_spec *spec;
172 int i;
173
174 for (i = 0, spec = city_report_specs; i < NUM_CREPORT_COLS; i++, spec++) {
175 fc_snprintf(text[i], n, "%*s\n%*s",
176 NEG_VAL(spec->width), spec->title1 ? spec->title1 : "",
177 NEG_VAL(spec->width), spec->title2 ? spec->title2 : "");
178 }
179 }
180
181 /****************************************************************************
182 CITY REPORT DIALOG
183 ****************************************************************************/
184
185 /****************************************************************************
186 Returns a new tree model for the city report.
187 ****************************************************************************/
city_report_dialog_store_new(void)188 static GtkListStore *city_report_dialog_store_new(void)
189 {
190 GType model_types[NUM_CREPORT_COLS + 1];
191 gint i;
192
193 /* City report data. */
194 for (i = 0; i < NUM_CREPORT_COLS; i++) {
195 model_types[i] = G_TYPE_STRING;
196 }
197
198 /* Specific gtk client data. */
199 model_types[i++] = G_TYPE_INT; /* CRD_COL_CITY_ID */
200
201 return gtk_list_store_newv(i, model_types);
202 }
203
204 /****************************************************************************
205 Set the values of the iterator.
206 ****************************************************************************/
city_model_set(GtkListStore * store,GtkTreeIter * iter,struct city * pcity)207 static void city_model_set(GtkListStore *store, GtkTreeIter *iter,
208 struct city *pcity)
209 {
210 struct city_report_spec *spec;
211 char buf[64];
212 gint i;
213
214 for (i = 0; i < NUM_CREPORT_COLS; i++) {
215 spec = city_report_specs + i;
216 fc_snprintf(buf, sizeof(buf), "%*s", NEG_VAL(spec->width),
217 spec->func(pcity, spec->data));
218 gtk_list_store_set(store, iter, i, buf, -1);
219 }
220 gtk_list_store_set(store, iter, CRD_COL_CITY_ID, pcity->id, -1);
221 }
222
223 /****************************************************************************
224 Set the values of the iterator.
225 ****************************************************************************/
city_model_get(GtkTreeModel * model,GtkTreeIter * iter)226 static struct city *city_model_get(GtkTreeModel *model, GtkTreeIter *iter)
227 {
228 struct city *pcity;
229 int id;
230
231 gtk_tree_model_get(model, iter, CRD_COL_CITY_ID, &id, -1);
232 pcity = game_city_by_number(id);
233 return ((NULL != pcity
234 && client_has_player()
235 && city_owner(pcity) != client_player())
236 ? NULL : pcity);
237 }
238
239 /****************************************************************************
240 Return TRUE if 'iter' has been set to the city row.
241 ****************************************************************************/
city_model_find(GtkTreeModel * model,GtkTreeIter * iter,const struct city * pcity)242 static gboolean city_model_find(GtkTreeModel *model, GtkTreeIter *iter,
243 const struct city *pcity)
244 {
245 const int searched = pcity->id;
246 int id;
247
248 if (gtk_tree_model_get_iter_first(model, iter)) {
249 do {
250 gtk_tree_model_get(model, iter, CRD_COL_CITY_ID, &id, -1);
251 if (searched == id) {
252 return TRUE;
253 }
254 } while (gtk_tree_model_iter_next(model, iter));
255 }
256 return FALSE;
257 }
258
259 /****************************************************************************
260 Fill the model with the current configuration.
261 ****************************************************************************/
city_model_fill(GtkListStore * store,GtkTreeSelection * selection,GHashTable * select)262 static void city_model_fill(GtkListStore *store,
263 GtkTreeSelection *selection, GHashTable *select)
264 {
265 GtkTreeIter iter;
266
267 if (client_has_player()) {
268 city_list_iterate(client_player()->cities, pcity) {
269 gtk_list_store_append(store, &iter);
270 city_model_set(store, &iter, pcity);
271 if (NULL != select
272 && g_hash_table_remove(select, GINT_TO_POINTER(pcity->id))) {
273 gtk_tree_selection_select_iter(selection, &iter);
274 }
275 } city_list_iterate_end;
276 } else {
277 /* Global observer case. */
278 cities_iterate(pcity) {
279 gtk_list_store_append(store, &iter);
280 city_model_set(store, &iter, pcity);
281 if (NULL != select
282 && g_hash_table_remove(select, GINT_TO_POINTER(pcity->id))) {
283 gtk_tree_selection_select_iter(selection, &iter);
284 }
285 } cities_iterate_end;
286 }
287 }
288
289 /****************************************************************
290 Popup the city report dialog, and optionally raise it.
291 ****************************************************************/
city_report_dialog_popup(bool raise)292 void city_report_dialog_popup(bool raise)
293 {
294 if(!city_dialog_shell) {
295 city_dialog_shell_is_modal = FALSE;
296
297 create_city_report_dialog(FALSE);
298
299 select_menu_cached = FALSE;
300 }
301
302 gui_dialog_present(city_dialog_shell);
303 hilite_cities_from_canvas();
304 if (raise) {
305 gui_dialog_raise(city_dialog_shell);
306 }
307 }
308
309 /****************************************************************
310 Closes the city report dialog.
311 ****************************************************************/
city_report_dialog_popdown(void)312 void city_report_dialog_popdown(void)
313 {
314 if (city_dialog_shell) {
315 gui_dialog_destroy(city_dialog_shell);
316 }
317 }
318
319 /****************************************************************
320 Make submenu listing possible build targets
321 *****************************************************************/
append_impr_or_unit_to_menu_item(GtkMenuItem * parent_item,bool append_units,bool append_wonders,enum city_operation_type city_operation,TestCityFunc test_func,GCallback callback,int size)322 static void append_impr_or_unit_to_menu_item(GtkMenuItem *parent_item,
323 bool append_units,
324 bool append_wonders,
325 enum city_operation_type
326 city_operation,
327 TestCityFunc test_func,
328 GCallback callback,
329 int size)
330 {
331 GtkWidget *menu;
332 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
333 struct item items[MAX_NUM_PRODUCTION_TARGETS];
334 int i, item, targets_used;
335 char *row[4];
336 char buf[4][64];
337
338 GtkSizeGroup *group[3];
339 const char *markup[3] = {
340 "weight=\"bold\"",
341 "",
342 ""
343 };
344
345 menu = gtk_menu_new();
346 gtk_menu_item_set_submenu(parent_item, menu);
347
348 if (city_operation != CO_NONE) {
349 GPtrArray *selected;
350 ITree it;
351 int num_selected = 0;
352 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
353 struct city **data;
354
355 selected = g_ptr_array_sized_new(size);
356
357 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
358 struct city *pcity;
359
360 if (!itree_is_selected(city_selection, &it)
361 || !(pcity = city_model_get(model, TREE_ITER_PTR(it)))) {
362 continue;
363 }
364
365 g_ptr_array_add(selected, pcity);
366 num_selected++;
367 }
368
369 data = (struct city **)g_ptr_array_free(selected, FALSE);
370 targets_used
371 = collect_production_targets(targets, data, num_selected, append_units,
372 append_wonders, TRUE, test_func);
373 g_free(data);
374 } else {
375 targets_used = collect_production_targets(targets, NULL, 0, append_units,
376 append_wonders, FALSE,
377 test_func);
378 }
379
380 name_and_sort_items(targets, targets_used, items,
381 city_operation != CO_NONE, NULL);
382
383 for (i = 0; i < 4; i++) {
384 row[i] = buf[i];
385 }
386
387 g_object_set_data(G_OBJECT(menu), "freeciv_test_func", test_func);
388 g_object_set_data(G_OBJECT(menu), "freeciv_city_operation",
389 GINT_TO_POINTER(city_operation));
390
391 for (i = 0; i < 3; i++) {
392 group[i] = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
393 }
394
395 for (item = 0; item < targets_used; item++) {
396 struct universal target = items[item].item;
397 GtkWidget *menu_item, *hbox, *label;
398 char txt[256];
399
400 get_city_dialog_production_row(row, sizeof(buf[0]), &target, NULL);
401
402 menu_item = gtk_menu_item_new();
403 hbox = gtk_hbox_new(FALSE, 18);
404 gtk_container_add(GTK_CONTAINER(menu_item), hbox);
405
406 for (i = 0; i < 3; i++) {
407 if (row[i][0] == '\0') {
408 continue;
409 }
410
411 if (city_operation == CO_SELL && i != 0) {
412 continue;
413 }
414
415 fc_snprintf(txt, ARRAY_SIZE(txt), "<span %s>%s</span>",
416 markup[i], row[i]);
417
418 label = gtk_label_new(NULL);
419 gtk_label_set_markup(GTK_LABEL(label), txt);
420
421 if (i < 2) {
422 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
423 } else {
424 gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
425 }
426
427 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, FALSE, 0);
428 gtk_size_group_add_widget(group[i], label);
429 }
430
431 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
432 g_signal_connect(menu_item, "activate", callback,
433 GINT_TO_POINTER(cid_encode(target)));
434 }
435
436 for (i = 0; i < 3; i++) {
437 g_object_unref(group[i]);
438 }
439
440 gtk_widget_show_all(menu);
441
442 gtk_widget_set_sensitive(GTK_WIDGET(parent_item), (targets_used > 0));
443 }
444
445 /****************************************************************************
446 Change the production of one single selected city.
447 ****************************************************************************/
impr_or_unit_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)448 static void impr_or_unit_iterate(GtkTreeModel *model, GtkTreePath *path,
449 GtkTreeIter *iter, gpointer data)
450 {
451 struct universal target = cid_decode(GPOINTER_TO_INT(data));
452 struct city *pcity = city_model_get(model, iter);
453
454 if (NULL != pcity) {
455 city_change_production(pcity, &target);
456 }
457 }
458
459 /****************************************************************************
460 Called by select_impr_or_unit_callback for each city that is selected in
461 the city list dialog to have a object appended to the worklist. Sends a
462 packet adding the item to the end of the worklist.
463 ****************************************************************************/
worklist_last_impr_or_unit_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)464 static void worklist_last_impr_or_unit_iterate(GtkTreeModel *model,
465 GtkTreePath *path,
466 GtkTreeIter *iter,
467 gpointer data)
468 {
469 struct universal target = cid_decode(GPOINTER_TO_INT(data));
470 struct city *pcity = city_model_get(model, iter);
471
472 if (NULL != pcity) {
473 (void) city_queue_insert(pcity, -1, &target);
474 }
475 /* perhaps should warn the user if not successful? */
476 }
477
478 /****************************************************************************
479 Called by select_impr_or_unit_callback for each city that is selected in
480 the city list dialog to have a object inserted first to the worklist.
481 Sends a packet adding the current production to the first place after the
482 current production of the worklist. Then changes the production to the
483 requested item.
484 ****************************************************************************/
worklist_first_impr_or_unit_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)485 static void worklist_first_impr_or_unit_iterate(GtkTreeModel *model,
486 GtkTreePath *path,
487 GtkTreeIter *iter,
488 gpointer data)
489 {
490 struct universal target = cid_decode(GPOINTER_TO_INT(data));
491 struct city *pcity = city_model_get(model, iter);
492
493 if (NULL != pcity) {
494 (void) city_queue_insert(pcity, 0, &target);
495 }
496 /* perhaps should warn the user if not successful? */
497 }
498
499 /****************************************************************************
500 Called by select_impr_or_unit_callback for each city that is selected in
501 the city list dialog to have a object added next to the worklist. Sends a
502 packet adding the item to the first place after the current production of
503 the worklist.
504 ****************************************************************************/
worklist_next_impr_or_unit_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)505 static void worklist_next_impr_or_unit_iterate(GtkTreeModel *model,
506 GtkTreePath *path,
507 GtkTreeIter *iter,
508 gpointer data)
509 {
510 struct universal target = cid_decode(GPOINTER_TO_INT(data));
511 struct city *pcity = city_model_get(model, iter);
512
513 if (NULL != pcity) {
514 (void) city_queue_insert(pcity, 1, &target);
515 }
516 /* perhaps should warn the user if not successful? */
517 }
518
519 /****************************************************************************
520 Called by select_impr_or_unit_callback for each city that is selected in
521 the city list dialog to have an object added before the last position in
522 the worklist.
523 ****************************************************************************/
worklist_next_to_last_impr_or_unit_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)524 static void worklist_next_to_last_impr_or_unit_iterate(GtkTreeModel *model,
525 GtkTreePath *path,
526 GtkTreeIter *iter,
527 gpointer data)
528 {
529 struct universal target = cid_decode(GPOINTER_TO_INT(data));
530 struct city *pcity = city_model_get(model, iter);
531
532 if (NULL != pcity) {
533 city_queue_insert(pcity, worklist_length(&pcity->worklist), &target);
534 }
535 }
536
537 /****************************************************************************
538 Iterate the cities going to sell.
539 ****************************************************************************/
sell_impr_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)540 static void sell_impr_iterate(GtkTreeModel *model, GtkTreePath *path,
541 GtkTreeIter *iter, gpointer data)
542 {
543 struct sell_data *sd = (struct sell_data *) data;
544 struct city *pcity = city_model_get(model, iter);
545
546 if (NULL != pcity
547 && !pcity->did_sell
548 && city_has_building(pcity, sd->target)) {
549 sd->count++;
550 sd->gold += impr_sell_gold(sd->target);
551 city_sell_improvement(pcity, improvement_number(sd->target));
552 }
553 }
554
555 /****************************************************************************
556 Some build target, either improvement or unit, has been selected from
557 some menu.
558 ****************************************************************************/
select_impr_or_unit_callback(GtkWidget * wdg,gpointer data)559 static void select_impr_or_unit_callback(GtkWidget *wdg, gpointer data)
560 {
561 struct universal target = cid_decode(GPOINTER_TO_INT(data));
562 GObject *parent = G_OBJECT(wdg->parent);
563 TestCityFunc test_func = g_object_get_data(parent, "freeciv_test_func");
564 enum city_operation_type city_operation =
565 GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_city_operation"));
566
567 /* if this is not a city operation: */
568 if (city_operation == CO_NONE) {
569 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
570 ITree it;
571
572 gtk_tree_selection_unselect_all(city_selection);
573 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
574 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
575
576 if (NULL != pcity && test_func(pcity, &target)) {
577 itree_select(city_selection, &it);
578 }
579 }
580 } else {
581 GtkTreeSelectionForeachFunc foreach_func;
582 connection_do_buffer(&client.conn);
583 switch (city_operation) {
584 case CO_LAST:
585 gtk_tree_selection_selected_foreach(city_selection,
586 worklist_last_impr_or_unit_iterate,
587 GINT_TO_POINTER(cid_encode(target)));
588 break;
589 case CO_CHANGE:
590 gtk_tree_selection_selected_foreach(city_selection,
591 impr_or_unit_iterate,
592 GINT_TO_POINTER(cid_encode(target)));
593 break;
594 case CO_FIRST:
595 gtk_tree_selection_selected_foreach(city_selection,
596 worklist_first_impr_or_unit_iterate,
597 GINT_TO_POINTER(cid_encode(target)));
598 break;
599 case CO_NEXT:
600 gtk_tree_selection_selected_foreach(city_selection,
601 worklist_next_impr_or_unit_iterate,
602 GINT_TO_POINTER(cid_encode(target)));
603 break;
604 case CO_NEXT_TO_LAST:
605 foreach_func = worklist_next_to_last_impr_or_unit_iterate;
606 gtk_tree_selection_selected_foreach(city_selection, foreach_func,
607 GINT_TO_POINTER(cid_encode(target)));
608 break;
609 case CO_SELL:
610 fc_assert_action(target.kind == VUT_IMPROVEMENT, break);
611 {
612 struct impr_type *building = target.value.building;
613 struct sell_data sd = { 0, 0, building };
614 GtkWidget *w;
615 gint res;
616 gchar *buf;
617 const char *imprname = improvement_name_translation(building);
618
619 /* Ask confirmation */
620 buf = g_strdup_printf(_("Are you sure you want to sell those %s?"), imprname);
621 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
622 GTK_MESSAGE_QUESTION,
623 GTK_BUTTONS_YES_NO, "%s", buf);
624 g_free(buf);
625 res = gtk_dialog_run(GTK_DIALOG(w)); /* Synchron. */
626 gtk_widget_destroy(w);
627 if (res == GTK_RESPONSE_NO) {
628 break;
629 }
630
631 gtk_tree_selection_selected_foreach(city_selection,
632 sell_impr_iterate, &sd);
633 if (sd.count > 0) {
634 /* FIXME: plurality of sd.count is ignored! */
635 /* TRANS: "Sold 3 Harbor for 90 gold." (Pluralisation is in gold --
636 * second %d -- not in buildings.) */
637 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
638 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
639 PL_("Sold %d %s for %d gold.",
640 "Sold %d %s for %d gold.",
641 sd.gold),
642 sd.count, imprname, sd.gold);
643 } else {
644 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
645 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
646 _("No %s could be sold."),
647 imprname);
648 }
649
650 g_signal_connect(w, "response",
651 G_CALLBACK(gtk_widget_destroy), NULL);
652 gtk_window_present(GTK_WINDOW(w)); /* Asynchron. */
653 }
654 break;
655 case CO_NONE:
656 break;
657 }
658 connection_do_unbuffer(&client.conn);
659 }
660 }
661
662 /****************************************************************************
663 CMA callback.
664 ****************************************************************************/
cma_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)665 static void cma_iterate(GtkTreeModel *model, GtkTreePath *path,
666 GtkTreeIter *iter, gpointer data)
667 {
668 struct city *pcity = city_model_get(model, iter);
669 int idx = GPOINTER_TO_INT(data);
670
671 if (NULL != pcity) {
672 if (CMA_NONE == idx) {
673 cma_release_city(pcity);
674 } else {
675 cma_put_city_under_agent(pcity, cmafec_preset_get_parameter(idx));
676 }
677 refresh_city_dialog(pcity);
678 }
679 }
680
681 /****************************************************************
682 Called when one clicks on an CMA item to make a selection or to
683 change a selection's preset.
684 *****************************************************************/
select_cma_callback(GtkWidget * w,gpointer data)685 static void select_cma_callback(GtkWidget * w, gpointer data)
686 {
687 int idx = GPOINTER_TO_INT(data);
688 GObject *parent = G_OBJECT(w->parent);
689 bool change_cma =
690 GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_change_cma"));
691 struct cm_parameter parameter;
692
693 /* If this is not the change button but the select cities button. */
694 if (!change_cma) {
695 ITree it;
696 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
697
698 gtk_tree_selection_unselect_all(city_selection);
699 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
700 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
701 int controlled;
702 bool select;
703
704 if (NULL == pcity) {
705 continue;
706 }
707 controlled = cma_is_city_under_agent(pcity, ¶meter);
708 select = FALSE;
709
710 if (idx == CMA_NONE) {
711 /* CMA_NONE selects not-controlled, all others require controlled */
712 if (!controlled) {
713 select = TRUE;
714 }
715 } else if (controlled) {
716 if (idx == CMA_CUSTOM) {
717 if (cmafec_preset_get_index_of_parameter(¶meter) == -1) {
718 select = TRUE;
719 }
720 } else if (cm_are_parameter_equal(¶meter,
721 cmafec_preset_get_parameter(idx))) {
722 select = TRUE;
723 }
724 }
725
726 if (select) {
727 itree_select(city_selection, &it);
728 }
729 }
730 } else {
731 gtk_tree_selection_selected_foreach(city_selection,
732 cma_iterate, GINT_TO_POINTER(idx));
733 }
734 }
735
736 /****************************************************************
737 Create the cma entries in the change menu and the select menu. The
738 indices CMA_NONE and CMA_CUSTOM are special.
739 CMA_NONE signifies a preset of "none" and CMA_CUSTOM a
740 "custom" preset.
741 *****************************************************************/
append_cma_to_menu_item(GtkMenuItem * parent_item,bool change_cma)742 static void append_cma_to_menu_item(GtkMenuItem *parent_item, bool change_cma)
743 {
744 GtkWidget *menu;
745 int i;
746 struct cm_parameter parameter;
747 GtkWidget *w;
748
749 w = gtk_menu_item_get_submenu(parent_item);
750 if (w != NULL && GTK_WIDGET_VISIBLE(w)) {
751 return;
752 }
753
754 if (!can_client_issue_orders()) {
755 gtk_menu_item_set_submenu(parent_item, NULL);
756 return;
757 }
758 menu = gtk_menu_new();
759 gtk_menu_item_set_submenu(parent_item, menu);
760
761 if (change_cma) {
762 w = gtk_menu_item_new_with_label(_("none"));
763 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
764 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
765 GINT_TO_POINTER(CMA_NONE));
766 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(CMA_NONE)) == CMA_NONE);
767
768 for (i = 0; i < cmafec_preset_num(); i++) {
769 w = gtk_menu_item_new_with_label(cmafec_preset_get_descr(i));
770 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
771 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
772 GINT_TO_POINTER(i));
773 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(i)) == i);
774 }
775 } else {
776 /* search for a "none" */
777 int found;
778
779 found = 0;
780 city_list_iterate(client.conn.playing->cities, pcity) {
781 if (!cma_is_city_under_agent(pcity, NULL)) {
782 found = 1;
783 break;
784 }
785 } city_list_iterate_end;
786
787 if (found) {
788 w = gtk_menu_item_new_with_label(_("none"));
789 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
790 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
791 GINT_TO_POINTER(CMA_NONE));
792 }
793
794 /*
795 * Search for a city that's under custom (not preset) agent. Might
796 * take a lonnggg time.
797 */
798 found = 0;
799 city_list_iterate(client.conn.playing->cities, pcity) {
800 if (cma_is_city_under_agent(pcity, ¶meter) &&
801 cmafec_preset_get_index_of_parameter(¶meter) == -1) {
802 found = 1;
803 break;
804 }
805 } city_list_iterate_end;
806
807 if (found) {
808 /* we found city that's under agent but not a preset */
809 w = gtk_menu_item_new_with_label(_("custom"));
810
811 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
812 g_signal_connect(w, "activate",
813 G_CALLBACK(select_cma_callback), GINT_TO_POINTER(CMA_CUSTOM));
814 }
815
816 /* only fill in presets that are being used. */
817 for (i = 0; i < cmafec_preset_num(); i++) {
818 found = 0;
819 city_list_iterate(client.conn.playing->cities, pcity) {
820 if (cma_is_city_under_agent(pcity, ¶meter) &&
821 cm_are_parameter_equal(¶meter,
822 cmafec_preset_get_parameter(i))) {
823 found = 1;
824 break;
825 }
826 } city_list_iterate_end;
827 if (found) {
828 w = gtk_menu_item_new_with_label(cmafec_preset_get_descr(i));
829
830 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
831 g_signal_connect(w, "activate",
832 G_CALLBACK(select_cma_callback), GINT_TO_POINTER(i));
833 }
834 }
835 }
836
837 g_object_set_data(G_OBJECT(menu), "freeciv_change_cma",
838 GINT_TO_POINTER(change_cma));
839 gtk_widget_show_all(menu);
840 }
841
842 /****************************************************************************
843 Helper function to append a worklist to the current work list of one city
844 in the city report. This function is called over all selected rows in the
845 list view.
846 ****************************************************************************/
append_worklist_foreach(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)847 static void append_worklist_foreach(GtkTreeModel *model, GtkTreePath *path,
848 GtkTreeIter *iter, gpointer data)
849 {
850 const struct worklist *pwl = data;
851 struct city *pcity = city_model_get(model, iter);
852
853 fc_assert_ret(pwl != NULL);
854
855 if (NULL != pcity) {
856 city_queue_insert_worklist(pcity, -1, pwl);
857 }
858 }
859
860 /**************************************************************************
861 Menu item callback to append the global worklist associated with this
862 item to the worklists of all selected cities. The worklist pointer is
863 passed in 'data'.
864 **************************************************************************/
append_worklist_callback(GtkMenuItem * menuitem,gpointer data)865 static void append_worklist_callback(GtkMenuItem *menuitem, gpointer data)
866 {
867 struct global_worklist *pgwl =
868 global_worklist_by_id(GPOINTER_TO_INT(data));
869
870 fc_assert_ret(city_selection != NULL);
871
872 if (!pgwl) {
873 /* Maybe removed by an other way, not an error. */
874 return;
875 }
876
877 gtk_tree_selection_selected_foreach(city_selection,
878 append_worklist_foreach,
879 (gpointer) global_worklist_get(pgwl));
880 }
881
882 /****************************************************************************
883 Helper function to set a worklist for one city in the city report. This
884 function is called over all selected rows in the list view.
885 ****************************************************************************/
set_worklist_foreach(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)886 static void set_worklist_foreach(GtkTreeModel *model, GtkTreePath *path,
887 GtkTreeIter *iter, gpointer data)
888 {
889 const struct worklist *pwl = data;
890 struct city *pcity = city_model_get(model, iter);
891
892 fc_assert_ret(pwl != NULL);
893
894 if (NULL != pcity) {
895 city_set_queue(pcity, pwl);
896 }
897 }
898
899 /**************************************************************************
900 Menu item callback to set a city's worklist to the global worklist
901 associated with this menu item. The worklist pointer is passed in 'data'.
902 **************************************************************************/
set_worklist_callback(GtkMenuItem * menuitem,gpointer data)903 static void set_worklist_callback(GtkMenuItem *menuitem, gpointer data)
904 {
905 struct global_worklist *pgwl =
906 global_worklist_by_id(GPOINTER_TO_INT(data));
907
908 fc_assert_ret(city_selection != NULL);
909 gtk_tree_selection_selected_foreach(city_selection, set_worklist_foreach,
910 (gpointer) global_worklist_get(pgwl));
911
912 if (!pgwl) {
913 /* Maybe removed by an other way, not an error. */
914 return;
915 }
916
917 gtk_tree_selection_selected_foreach(city_selection,
918 set_worklist_foreach,
919 (gpointer) global_worklist_get(pgwl));
920 }
921
922 /**************************************************************************
923 Empty and refill the submenu of the menu item passed as 'data'. The menu
924 will be filled with menu items corresponding to the global worklists.
925 **************************************************************************/
production_menu_shown(GtkWidget * widget,gpointer data)926 static void production_menu_shown(GtkWidget *widget, gpointer data)
927 {
928 GtkWidget *menu, *item;
929 GtkMenuItem *parent_item;
930 GCallback callback;
931 int count = 0;
932
933 parent_item = data;
934 fc_assert_ret(parent_item != NULL);
935 fc_assert_ret(GTK_IS_MENU_ITEM(parent_item));
936
937 callback = g_object_get_data(G_OBJECT(parent_item), "item_callback");
938 fc_assert_ret(callback != NULL);
939
940 menu = gtk_menu_item_get_submenu(parent_item);
941 if (menu != NULL && GTK_WIDGET_VISIBLE(menu)) {
942 gtk_menu_shell_deactivate(GTK_MENU_SHELL(menu));
943 }
944
945 if (menu == NULL) {
946 menu = gtk_menu_new();
947 gtk_menu_item_set_submenu(parent_item, menu);
948 }
949
950 if (!can_client_issue_orders()) {
951 return;
952 }
953
954 gtk_container_forall(GTK_CONTAINER(menu),
955 (GtkCallback) gtk_widget_destroy, NULL);
956
957 global_worklists_iterate(pgwl) {
958 item = gtk_menu_item_new_with_label(global_worklist_name(pgwl));
959 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
960 g_signal_connect(item, "activate", callback,
961 GINT_TO_POINTER(global_worklist_id(pgwl)));
962 count++;
963 } global_worklists_iterate_end;
964
965 if (count == 0) {
966 item = gtk_menu_item_new_with_label(_("(no worklists defined)"));
967 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
968 }
969
970 gtk_widget_show_all(menu);
971 }
972
973 /****************************************************************
974 Update city report views
975 *****************************************************************/
city_report_update_views(void)976 static void city_report_update_views(void)
977 {
978 struct city_report_spec *spec;
979 GtkTreeView *view;
980 GtkTreeViewColumn *col;
981 GList *columns, *p;
982
983 view = GTK_TREE_VIEW(city_view);
984 fc_assert_ret(view != NULL);
985
986 columns = gtk_tree_view_get_columns(view);
987
988 for (p = columns; p != NULL; p = p->next) {
989 col = p->data;
990 spec = g_object_get_data(G_OBJECT(col), "city_report_spec");
991 gtk_tree_view_column_set_visible(col, spec->show);
992 }
993
994 g_list_free(columns);
995 }
996
997 /****************************************************************
998 User has toggled some column viewing option
999 *****************************************************************/
toggle_view(GtkCheckMenuItem * item,gpointer data)1000 static void toggle_view(GtkCheckMenuItem *item, gpointer data)
1001 {
1002 struct city_report_spec *spec = data;
1003
1004 spec->show ^= 1;
1005 city_report_update_views();
1006 }
1007
1008 /****************************************************************
1009 Create view menu for city report menubar.
1010 *****************************************************************/
update_view_menu(GtkWidget * show_item)1011 static void update_view_menu(GtkWidget *show_item)
1012 {
1013 GtkWidget *menu, *item;
1014 struct city_report_spec *spec;
1015 int i;
1016
1017 menu = gtk_menu_new();
1018 for(i=0, spec=city_report_specs+i; i<NUM_CREPORT_COLS; i++, spec++) {
1019 item = gtk_check_menu_item_new_with_label(spec->explanation);
1020 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1021 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), spec->show);
1022 g_signal_connect(item, "toggled", G_CALLBACK(toggle_view), (gpointer)spec);
1023 }
1024 gtk_menu_item_set_submenu(GTK_MENU_ITEM(show_item), menu);
1025 }
1026
1027 /****************************************************************
1028 Create menubar for city report
1029 *****************************************************************/
create_city_report_menubar(void)1030 static GtkWidget *create_city_report_menubar(void)
1031 {
1032 GtkWidget *vbox, *sep, *menubar, *menu, *item;
1033
1034 vbox = gtk_vbox_new(FALSE, 0);
1035 sep = gtk_hseparator_new();
1036 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
1037
1038 menubar = gtk_aux_menu_bar_new();
1039 gtk_box_pack_start(GTK_BOX(vbox), menubar, TRUE, TRUE, 0);
1040
1041 item = gtk_menu_item_new_with_mnemonic(_("_Production"));
1042 city_production_command = item;
1043 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1044
1045 menu = gtk_menu_new();
1046 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1047
1048 item = gtk_menu_item_new_with_mnemonic(_("Chan_ge"));
1049 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1050 create_change_menu(item);
1051
1052 item = gtk_menu_item_new_with_mnemonic(_("Add _First"));
1053 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1054 create_first_menu(item);
1055
1056 item = gtk_menu_item_new_with_mnemonic(_("Add _Next"));
1057 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1058 create_next_menu(item);
1059
1060 item = gtk_menu_item_new_with_mnemonic(_("Add _2nd Last"));
1061 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1062 create_next_to_last_menu(item);
1063
1064 item = gtk_menu_item_new_with_mnemonic(_("Add _Last"));
1065 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1066 create_last_menu(item);
1067
1068 item = gtk_separator_menu_item_new();
1069 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1070
1071 item = gtk_menu_item_new_with_label(_("Set Worklist"));
1072 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1073 g_object_set_data(G_OBJECT(item), "item_callback",
1074 set_worklist_callback);
1075 g_signal_connect(menu, "show", G_CALLBACK(production_menu_shown), item);
1076
1077 item = gtk_menu_item_new_with_label(_("Append Worklist"));
1078 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1079 g_object_set_data(G_OBJECT(item), "item_callback",
1080 append_worklist_callback);
1081 g_signal_connect(menu, "show", G_CALLBACK(production_menu_shown), item);
1082
1083 item = gtk_menu_item_new_with_mnemonic(_("Clear _Worklist"));
1084 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1085 g_signal_connect(item, "activate",
1086 G_CALLBACK(city_clear_worklist_callback), NULL);
1087
1088 item = gtk_menu_item_new_with_mnemonic(_("Gover_nor"));
1089 city_governor_command = item;
1090 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1091 append_cma_to_menu_item(GTK_MENU_ITEM(item), TRUE);
1092
1093 item = gtk_menu_item_new_with_mnemonic(_("S_ell"));
1094 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1095 city_sell_command = item;
1096 create_sell_menu(item);
1097
1098 item = gtk_menu_item_new_with_mnemonic(_("_Select"));
1099 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1100 create_select_menu(item);
1101
1102 item = gtk_menu_item_new_with_mnemonic(_("_Display"));
1103 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1104 update_view_menu(item);
1105 return vbox;
1106 }
1107
1108 /****************************************************************************
1109 Sort callback.
1110 ****************************************************************************/
cityrep_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)1111 static gint cityrep_sort_func(GtkTreeModel *model, GtkTreeIter *a,
1112 GtkTreeIter *b, gpointer data)
1113 {
1114 gint col = GPOINTER_TO_INT(data);
1115 const gchar *str1, *str2;
1116
1117 gtk_tree_model_get(model, a, col, &str1, -1);
1118 gtk_tree_model_get(model, b, col, &str2, -1);
1119
1120 return cityrepfield_compare(str1, str2);
1121 }
1122
1123 /****************************************************************
1124 Create city report dialog.
1125 *****************************************************************/
create_city_report_dialog(bool make_modal)1126 static void create_city_report_dialog(bool make_modal)
1127 {
1128 static char **titles;
1129 static char (*buf)[128];
1130 struct city_report_spec *spec;
1131
1132 GtkWidget *w, *sw, *menubar;
1133 int i;
1134
1135 gui_dialog_new(&city_dialog_shell, GTK_NOTEBOOK(top_notebook), NULL, TRUE);
1136 gui_dialog_set_title(city_dialog_shell, _("Cities"));
1137
1138 gui_dialog_set_default_size(city_dialog_shell, -1, 420);
1139
1140 gui_dialog_response_set_callback(city_dialog_shell,
1141 city_command_callback);
1142
1143 /* menubar */
1144 menubar = create_city_report_menubar();
1145 gui_dialog_add_widget(city_dialog_shell, menubar);
1146
1147 /* buttons */
1148 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_ZOOM_FIT,
1149 _("Cen_ter"), CITY_CENTER);
1150 city_center_command = w;
1151
1152 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_ZOOM_IN,
1153 _("_Inspect"), CITY_POPUP);
1154 city_popup_command = w;
1155
1156 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_EXECUTE,
1157 _("_Buy"), CITY_BUY);
1158 city_buy_command = w;
1159
1160 city_total_buy_cost_label = gtk_label_new(NULL);
1161 gtk_label_set_ellipsize(GTK_LABEL(city_total_buy_cost_label),
1162 PANGO_ELLIPSIZE_START);
1163 gtk_box_pack_end(GTK_BOX(city_dialog_shell->action_area),
1164 city_total_buy_cost_label, TRUE, TRUE, 0);
1165
1166 gui_dialog_set_default_response(city_dialog_shell,
1167 GTK_RESPONSE_CLOSE);
1168
1169 /* tree view */
1170 buf = fc_realloc(buf, NUM_CREPORT_COLS * sizeof(buf[0]));
1171 titles = fc_realloc(titles, NUM_CREPORT_COLS * sizeof(titles[0]));
1172 for (i = 0; i < NUM_CREPORT_COLS; i++) {
1173 titles[i] = buf[i];
1174 }
1175 get_city_table_header(titles, sizeof(buf[0]));
1176
1177 city_model = city_report_dialog_store_new();
1178
1179 city_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(city_model));
1180 g_object_unref(city_model);
1181 gtk_widget_set_name(city_view, "small_font");
1182 g_signal_connect(city_view, "row_activated",
1183 G_CALLBACK(city_activated_callback), NULL);
1184 city_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(city_view));
1185 gtk_tree_selection_set_mode(city_selection, GTK_SELECTION_MULTIPLE);
1186 g_signal_connect(city_selection, "changed",
1187 G_CALLBACK(city_selection_changed_callback), NULL);
1188
1189 for (i = 0, spec = city_report_specs; i < NUM_CREPORT_COLS; i++, spec++) {
1190 GtkWidget *header;
1191 GtkCellRenderer *renderer;
1192 GtkTreeViewColumn *col;
1193
1194 renderer = gtk_cell_renderer_text_new();
1195 col = gtk_tree_view_column_new_with_attributes(NULL, renderer,
1196 "text", i, NULL);
1197 header = gtk_label_new(titles[i]);
1198 gtk_widget_set_tooltip_text(header, spec->explanation);
1199 gtk_widget_show(header);
1200 gtk_tree_view_column_set_widget(col, header);
1201 gtk_tree_view_column_set_visible(col, spec->show);
1202 gtk_tree_view_column_set_sort_column_id(col, i);
1203 gtk_tree_view_column_set_reorderable(col, TRUE);
1204 g_object_set_data(G_OBJECT(col), "city_report_spec", spec);
1205 gtk_tree_view_append_column(GTK_TREE_VIEW(city_view), col);
1206 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(city_model), i,
1207 cityrep_sort_func, GINT_TO_POINTER(i),
1208 NULL);
1209 }
1210
1211 sw = gtk_scrolled_window_new(NULL, NULL);
1212 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1213 GTK_SHADOW_ETCHED_IN);
1214 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1215 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1216 gtk_container_add(GTK_CONTAINER(sw), city_view);
1217
1218 gtk_box_pack_start(GTK_BOX(city_dialog_shell->vbox),
1219 sw, TRUE, TRUE, 0);
1220
1221 city_model_fill(city_model, NULL, NULL);
1222 gui_dialog_show_all(city_dialog_shell);
1223
1224 city_selection_changed_callback(city_selection);
1225 }
1226
1227 /****************************************************************
1228 User has chosen to select all cities
1229 *****************************************************************/
city_select_all_callback(GtkMenuItem * item,gpointer data)1230 static void city_select_all_callback(GtkMenuItem *item, gpointer data)
1231 {
1232 gtk_tree_selection_select_all(city_selection);
1233 }
1234
1235 /****************************************************************
1236 User has chosen to unselect all cities
1237 *****************************************************************/
city_unselect_all_callback(GtkMenuItem * item,gpointer data)1238 static void city_unselect_all_callback(GtkMenuItem *item, gpointer data)
1239 {
1240 gtk_tree_selection_unselect_all(city_selection);
1241 }
1242
1243 /****************************************************************
1244 User has chosen to invert selection
1245 *****************************************************************/
city_invert_selection_callback(GtkMenuItem * item,gpointer data)1246 static void city_invert_selection_callback(GtkMenuItem *item, gpointer data)
1247 {
1248 ITree it;
1249 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1250
1251 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1252 if (itree_is_selected(city_selection, &it)) {
1253 itree_unselect(city_selection, &it);
1254 } else {
1255 itree_select(city_selection, &it);
1256 }
1257 }
1258 }
1259
1260 /****************************************************************
1261 User has chosen to select coastal cities
1262 *****************************************************************/
city_select_coastal_callback(GtkMenuItem * item,gpointer data)1263 static void city_select_coastal_callback(GtkMenuItem *item, gpointer data)
1264 {
1265 ITree it;
1266 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1267
1268 gtk_tree_selection_unselect_all(city_selection);
1269
1270 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1271 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1272
1273 if (NULL != pcity && is_terrain_class_near_tile(pcity->tile, TC_OCEAN)) {
1274 itree_select(city_selection, &it);
1275 }
1276 }
1277 }
1278
1279 /****************************************************************************
1280 Select all cities on the same continent.
1281 ****************************************************************************/
same_island_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1282 static void same_island_iterate(GtkTreeModel *model, GtkTreePath *path,
1283 GtkTreeIter *iter, gpointer data)
1284 {
1285 struct city *selected_pcity = city_model_get(model, iter);
1286 ITree it;
1287
1288 if (NULL == selected_pcity) {
1289 return;
1290 }
1291
1292 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1293 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1294
1295 if (NULL != pcity
1296 && (tile_continent(pcity->tile)
1297 == tile_continent(selected_pcity->tile))) {
1298 itree_select(city_selection, &it);
1299 }
1300 }
1301 }
1302
1303 /****************************************************************
1304 User has chosen to select all cities on same island
1305 *****************************************************************/
city_select_same_island_callback(GtkMenuItem * item,gpointer data)1306 static void city_select_same_island_callback(GtkMenuItem *item, gpointer data)
1307 {
1308 gtk_tree_selection_selected_foreach(city_selection,same_island_iterate,NULL);
1309 }
1310
1311 /****************************************************************
1312 User has chosen to select cities with certain target in production
1313 *****************************************************************/
city_select_building_callback(GtkMenuItem * item,gpointer data)1314 static void city_select_building_callback(GtkMenuItem *item, gpointer data)
1315 {
1316 enum production_class_type which = GPOINTER_TO_INT(data);
1317 ITree it;
1318 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1319
1320 gtk_tree_selection_unselect_all(city_selection);
1321
1322 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1323 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1324
1325 if (NULL != pcity
1326 && ((which == PCT_UNIT && VUT_UTYPE == pcity->production.kind)
1327 || (which == PCT_NORMAL_IMPROVEMENT
1328 && VUT_IMPROVEMENT == pcity->production.kind
1329 && !is_wonder(pcity->production.value.building))
1330 || (which == PCT_WONDER
1331 && VUT_IMPROVEMENT == pcity->production.kind
1332 && is_wonder(pcity->production.value.building)))) {
1333 itree_select(city_selection, &it);
1334 }
1335 }
1336 }
1337
1338 /****************************************************************************
1339 Buy the production in one single city.
1340 ****************************************************************************/
buy_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1341 static void buy_iterate(GtkTreeModel *model, GtkTreePath *path,
1342 GtkTreeIter *iter, gpointer data)
1343 {
1344 struct city *pcity = city_model_get(model, iter);
1345
1346 if (NULL != pcity) {
1347 cityrep_buy(pcity);
1348 }
1349 }
1350
1351 /****************************************************************************
1352 Center to one single city.
1353 ****************************************************************************/
center_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1354 static void center_iterate(GtkTreeModel *model, GtkTreePath *path,
1355 GtkTreeIter *iter, gpointer data)
1356 {
1357 struct city *pcity = city_model_get(model, iter);
1358
1359 if (NULL != pcity) {
1360 center_tile_mapcanvas(pcity->tile);
1361 }
1362 }
1363
1364 /****************************************************************************
1365 Popup the dialog of a single city.
1366 ****************************************************************************/
popup_iterate(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)1367 static void popup_iterate(GtkTreeModel *model, GtkTreePath *path,
1368 GtkTreeIter *iter, gpointer data)
1369 {
1370 struct city *pcity = city_model_get(model, iter);
1371
1372 if (NULL != pcity) {
1373 if (gui_options.center_when_popup_city) {
1374 center_tile_mapcanvas(pcity->tile);
1375 }
1376 popup_city_dialog(pcity);
1377 }
1378 }
1379
1380 /****************************************************************************
1381 gui_dialog response callback.
1382 ****************************************************************************/
city_command_callback(struct gui_dialog * dlg,int response,gpointer data)1383 static void city_command_callback(struct gui_dialog *dlg, int response,
1384 gpointer data)
1385 {
1386 switch (response) {
1387 case CITY_CENTER:
1388 if (1 == gtk_tree_selection_count_selected_rows(city_selection)) {
1389 /* Center to city doesn't make sense if many city are selected. */
1390 gtk_tree_selection_selected_foreach(city_selection, center_iterate,
1391 NULL);
1392 }
1393 break;
1394 case CITY_POPUP:
1395 gtk_tree_selection_selected_foreach(city_selection, popup_iterate, NULL);
1396 break;
1397 case CITY_BUY:
1398 gtk_tree_selection_selected_foreach(city_selection, buy_iterate, NULL);
1399 break;
1400 default:
1401 gui_dialog_destroy(dlg);
1402 break;
1403 }
1404 }
1405
1406 /****************************************************************
1407 User has selected city row from city report.
1408 *****************************************************************/
city_activated_callback(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)1409 static void city_activated_callback(GtkTreeView *view, GtkTreePath *path,
1410 GtkTreeViewColumn *col, gpointer data)
1411 {
1412 GtkTreeModel *model;
1413 GtkTreeIter iter;
1414 GdkModifierType mask;
1415
1416 model = gtk_tree_view_get_model(view);
1417
1418 if (!gtk_tree_model_get_iter(model, &iter, path)) {
1419 return;
1420 }
1421
1422 gdk_window_get_pointer(NULL, NULL, NULL, &mask);
1423
1424 if (!(mask & GDK_CONTROL_MASK)) {
1425 popup_iterate(model, path, &iter, NULL);
1426 } else {
1427 center_iterate(model, path, &iter, NULL);
1428 }
1429 }
1430
1431 /****************************************************************************
1432 Update the city report dialog
1433 ****************************************************************************/
real_city_report_dialog_update(void * unused)1434 void real_city_report_dialog_update(void *unused)
1435 {
1436 GHashTable *selected;
1437 ITree iter;
1438 gint city_id;
1439
1440 if (NULL == city_dialog_shell) {
1441 return;
1442 }
1443
1444 /* Save the selection. */
1445 selected = g_hash_table_new(NULL, NULL);
1446 for (itree_begin(GTK_TREE_MODEL(city_model), &iter);
1447 !itree_end(&iter); itree_next(&iter)) {
1448 if (itree_is_selected(city_selection, &iter)) {
1449 itree_get(&iter, CRD_COL_CITY_ID, &city_id, -1);
1450 g_hash_table_insert(selected, GINT_TO_POINTER(city_id), NULL);
1451 }
1452 }
1453
1454 /* Update and restore the selection. */
1455 gtk_list_store_clear(city_model);
1456 city_model_fill(city_model, city_selection, selected);
1457 g_hash_table_destroy(selected);
1458
1459 if (GTK_WIDGET_SENSITIVE(city_governor_command)) {
1460 append_cma_to_menu_item(GTK_MENU_ITEM(city_governor_command), TRUE);
1461 }
1462
1463 select_menu_cached = FALSE;
1464 }
1465
1466 /****************************************************************************
1467 Update the text for a single city in the city report
1468 ****************************************************************************/
real_city_report_update_city(struct city * pcity)1469 void real_city_report_update_city(struct city *pcity)
1470 {
1471 GtkTreeIter iter;
1472
1473 if (NULL == city_dialog_shell) {
1474 return;
1475 }
1476
1477 if (!city_model_find(GTK_TREE_MODEL(city_model), &iter, pcity)) {
1478 gtk_list_store_prepend(city_model, &iter);
1479 }
1480 city_model_set(city_model, &iter, pcity);
1481
1482 update_total_buy_cost();
1483 }
1484
1485 /****************************************************************
1486 Create submenu for changing production target
1487 *****************************************************************/
create_change_menu(GtkWidget * item)1488 static void create_change_menu(GtkWidget *item)
1489 {
1490 GtkWidget *menu;
1491
1492 menu = gtk_menu_new();
1493 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1494 g_signal_connect(menu, "show", G_CALLBACK(popup_change_menu), NULL);
1495
1496 change_units_item = gtk_menu_item_new_with_label(_("Units"));
1497 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_units_item);
1498 change_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1499 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_improvements_item);
1500 change_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1501 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_wonders_item);
1502 }
1503
1504 /****************************************************************
1505 Creates the last menu.
1506 *****************************************************************/
create_last_menu(GtkWidget * item)1507 static void create_last_menu(GtkWidget *item)
1508 {
1509 GtkWidget *menu;
1510
1511 menu = gtk_menu_new();
1512 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1513 g_signal_connect(menu, "show", G_CALLBACK(popup_last_menu), NULL);
1514
1515 last_units_item = gtk_menu_item_new_with_label(_("Units"));
1516 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_units_item);
1517 last_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1518 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_improvements_item);
1519 last_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1520 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_wonders_item);
1521 }
1522
1523 /****************************************************************
1524 Creates the first menu.
1525 *****************************************************************/
create_first_menu(GtkWidget * item)1526 static void create_first_menu(GtkWidget *item)
1527 {
1528 GtkWidget *menu;
1529
1530 menu = gtk_menu_new();
1531 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1532 g_signal_connect(menu, "show", G_CALLBACK(popup_first_menu), NULL);
1533
1534 first_units_item = gtk_menu_item_new_with_label(_("Units"));
1535 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_units_item);
1536 first_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1537 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_improvements_item);
1538 first_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1539 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_wonders_item);
1540 }
1541
1542 /****************************************************************
1543 Creates the next menu.
1544 *****************************************************************/
create_next_menu(GtkWidget * item)1545 static void create_next_menu(GtkWidget *item)
1546 {
1547 GtkWidget *menu;
1548
1549 menu = gtk_menu_new();
1550 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1551 g_signal_connect(menu, "show", G_CALLBACK(popup_next_menu), NULL);
1552
1553 next_units_item = gtk_menu_item_new_with_label(_("Units"));
1554 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_units_item);
1555 next_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1556 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_improvements_item);
1557 next_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1558 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_wonders_item);
1559 }
1560
1561 /**************************************************************************
1562 Append the "next to last" submenu to the given menu item.
1563 **************************************************************************/
create_next_to_last_menu(GtkWidget * parent_item)1564 static void create_next_to_last_menu(GtkWidget *parent_item)
1565 {
1566 GtkWidget *menu, *item;
1567
1568 menu = gtk_menu_new();
1569 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item), menu);
1570 g_signal_connect(menu, "show",
1571 G_CALLBACK(popup_next_to_last_menu), NULL);
1572
1573 item = gtk_menu_item_new_with_label(_("Units"));
1574 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1575 next_to_last_units_item = item;
1576
1577 item = gtk_menu_item_new_with_label(_("Improvements"));
1578 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1579 next_to_last_improvements_item = item;
1580
1581 item = gtk_menu_item_new_with_label(_("Wonders"));
1582 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1583 next_to_last_wonders_item = item;
1584 }
1585
1586 /****************************************************************
1587 Create the sell menu (empty).
1588 *****************************************************************/
create_sell_menu(GtkWidget * item)1589 static void create_sell_menu(GtkWidget *item)
1590 {
1591 GtkWidget *menu;
1592
1593 menu = gtk_menu_new();
1594 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1595 }
1596
1597
1598 /****************************************************************
1599 Pops up menu where user can select build target.
1600 *****************************************************************/
popup_change_menu(GtkMenuShell * menu,gpointer data)1601 static void popup_change_menu(GtkMenuShell *menu, gpointer data)
1602 {
1603 int n;
1604
1605 n = gtk_tree_selection_count_selected_rows(city_selection);
1606
1607 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_improvements_item),
1608 FALSE, FALSE, CO_CHANGE,
1609 can_city_build_now,
1610 G_CALLBACK(select_impr_or_unit_callback), n);
1611 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_units_item),
1612 TRUE, FALSE, CO_CHANGE,
1613 can_city_build_now,
1614 G_CALLBACK(select_impr_or_unit_callback), n);
1615 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_wonders_item),
1616 FALSE, TRUE, CO_CHANGE,
1617 can_city_build_now,
1618 G_CALLBACK(select_impr_or_unit_callback), n);
1619 }
1620
1621 /****************************************************************
1622 pops up the last menu.
1623 *****************************************************************/
popup_last_menu(GtkMenuShell * menu,gpointer data)1624 static void popup_last_menu(GtkMenuShell *menu, gpointer data)
1625 {
1626 int n;
1627
1628 n = gtk_tree_selection_count_selected_rows(city_selection);
1629
1630 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_improvements_item),
1631 FALSE, FALSE, CO_LAST,
1632 can_city_build_now,
1633 G_CALLBACK(select_impr_or_unit_callback), n);
1634 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_units_item),
1635 TRUE, FALSE, CO_LAST,
1636 can_city_build_now,
1637 G_CALLBACK(select_impr_or_unit_callback), n);
1638 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_wonders_item),
1639 FALSE, TRUE, CO_LAST,
1640 can_city_build_now,
1641 G_CALLBACK(select_impr_or_unit_callback), n);
1642 }
1643
1644 /****************************************************************
1645 pops up the first menu.
1646 *****************************************************************/
popup_first_menu(GtkMenuShell * menu,gpointer data)1647 static void popup_first_menu(GtkMenuShell *menu, gpointer data)
1648 {
1649 int n;
1650
1651 n = gtk_tree_selection_count_selected_rows(city_selection);
1652
1653 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_improvements_item),
1654 FALSE, FALSE, CO_FIRST,
1655 can_city_build_now,
1656 G_CALLBACK(select_impr_or_unit_callback), n);
1657 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_units_item),
1658 TRUE, FALSE, CO_FIRST,
1659 can_city_build_now,
1660 G_CALLBACK(select_impr_or_unit_callback), n);
1661 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_wonders_item),
1662 FALSE, TRUE, CO_FIRST,
1663 can_city_build_now,
1664 G_CALLBACK(select_impr_or_unit_callback), n);
1665 }
1666
1667 /****************************************************************
1668 pops up the next menu.
1669 *****************************************************************/
popup_next_menu(GtkMenuShell * menu,gpointer data)1670 static void popup_next_menu(GtkMenuShell *menu, gpointer data)
1671 {
1672 int n;
1673
1674 n = gtk_tree_selection_count_selected_rows(city_selection);
1675
1676 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_improvements_item),
1677 FALSE, FALSE, CO_NEXT,
1678 can_city_build_now,
1679 G_CALLBACK(select_impr_or_unit_callback), n);
1680 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_units_item),
1681 TRUE, FALSE, CO_NEXT,
1682 can_city_build_now,
1683 G_CALLBACK(select_impr_or_unit_callback), n);
1684 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_wonders_item),
1685 FALSE, TRUE, CO_NEXT,
1686 can_city_build_now,
1687 G_CALLBACK(select_impr_or_unit_callback), n);
1688 }
1689
1690 /**************************************************************************
1691 Re-create the submenus in the next-to-last production change menu.
1692 **************************************************************************/
popup_next_to_last_menu(GtkMenuShell * menu,gpointer data)1693 static void popup_next_to_last_menu(GtkMenuShell *menu, gpointer data)
1694 {
1695 GtkWidget *item;
1696 GCallback callback;
1697 int n;
1698
1699 fc_assert_ret(city_selection != NULL);
1700
1701 n = gtk_tree_selection_count_selected_rows(city_selection);
1702 callback = G_CALLBACK(select_impr_or_unit_callback);
1703
1704 item = next_to_last_improvements_item;
1705 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1706 FALSE, FALSE, CO_NEXT_TO_LAST,
1707 can_city_build_now,
1708 callback, n);
1709 item = next_to_last_units_item;
1710 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1711 TRUE, FALSE, CO_NEXT_TO_LAST,
1712 can_city_build_now,
1713 callback, n);
1714 item = next_to_last_wonders_item;
1715 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1716 FALSE, TRUE, CO_NEXT_TO_LAST,
1717 can_city_build_now,
1718 callback, n);
1719 }
1720
1721 /****************************************************************
1722 Same as can_city_sell_building(), but with universal argument.
1723 *****************************************************************/
can_city_sell_universal(const struct city * pcity,const struct universal * target)1724 static bool can_city_sell_universal(const struct city *pcity,
1725 const struct universal *target)
1726 {
1727 return (target->kind == VUT_IMPROVEMENT
1728 && can_city_sell_building(pcity, target->value.building));
1729 }
1730
1731 /****************************************************************
1732 Update the sell menu.
1733 *****************************************************************/
recreate_sell_menu(void)1734 static void recreate_sell_menu(void)
1735 {
1736 int n;
1737 GList *children;
1738 GtkWidget *menu;
1739
1740 n = gtk_tree_selection_count_selected_rows(city_selection);
1741 menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command));
1742 gtk_menu_popdown(GTK_MENU(menu));
1743
1744 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(city_sell_command),
1745 FALSE, FALSE, CO_SELL,
1746 can_city_sell_universal,
1747 G_CALLBACK(select_impr_or_unit_callback),
1748 n);
1749
1750 menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command));
1751 children = gtk_container_get_children(GTK_CONTAINER(menu));
1752
1753 n = g_list_length(children);
1754 gtk_widget_set_sensitive(city_sell_command, n > 0);
1755 g_list_free(children);
1756 }
1757
1758 /****************************************************************
1759 Creates select menu
1760 *****************************************************************/
create_select_menu(GtkWidget * item)1761 static void create_select_menu(GtkWidget *item)
1762 {
1763 GtkWidget *menu;
1764
1765 menu = gtk_menu_new();
1766 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1767 g_signal_connect(menu, "show", G_CALLBACK(popup_select_menu), NULL);
1768
1769 item = gtk_menu_item_new_with_label(_("All Cities"));
1770 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1771 g_signal_connect(item, "activate",
1772 G_CALLBACK(city_select_all_callback), NULL);
1773
1774 item = gtk_menu_item_new_with_label(_("No Cities"));
1775 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1776 g_signal_connect(item, "activate",
1777 G_CALLBACK(city_unselect_all_callback), NULL);
1778
1779 item = gtk_menu_item_new_with_label(_("Invert Selection"));
1780 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1781 g_signal_connect(item, "activate",
1782 G_CALLBACK(city_invert_selection_callback), NULL);
1783
1784
1785 item = gtk_separator_menu_item_new();
1786 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1787
1788
1789 item = gtk_menu_item_new_with_label(_("Building Units"));
1790 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1791 g_signal_connect(item, "activate",
1792 G_CALLBACK(city_select_building_callback),
1793 GINT_TO_POINTER(PCT_UNIT));
1794
1795 item = gtk_menu_item_new_with_label( _("Building Improvements"));
1796 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1797 g_signal_connect(item, "activate",
1798 G_CALLBACK(city_select_building_callback),
1799 GINT_TO_POINTER(PCT_NORMAL_IMPROVEMENT));
1800
1801 item = gtk_menu_item_new_with_label(_("Building Wonders"));
1802 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1803 g_signal_connect(item, "activate",
1804 G_CALLBACK(city_select_building_callback),
1805 GINT_TO_POINTER(PCT_WONDER));
1806
1807
1808 item = gtk_separator_menu_item_new();
1809 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1810
1811
1812 select_bunit_item =
1813 gtk_menu_item_new_with_label(_("Building Unit"));
1814 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bunit_item);
1815
1816 select_bimprovement_item =
1817 gtk_menu_item_new_with_label( _("Building Improvement"));
1818 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bimprovement_item);
1819
1820 select_bwonder_item =
1821 gtk_menu_item_new_with_label(_("Building Wonder"));
1822 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bwonder_item);
1823
1824
1825 item = gtk_separator_menu_item_new();
1826 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1827
1828
1829 item = gtk_menu_item_new_with_label(_("Coastal Cities"));
1830 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1831 g_signal_connect(item, "activate",
1832 G_CALLBACK(city_select_coastal_callback), NULL);
1833
1834 select_island_item = gtk_menu_item_new_with_label(_("Same Island"));
1835 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_island_item);
1836 g_signal_connect(select_island_item, "activate",
1837 G_CALLBACK(city_select_same_island_callback), NULL);
1838
1839
1840 item = gtk_separator_menu_item_new();
1841 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1842
1843
1844 select_supported_item = gtk_menu_item_new_with_label(_("Supported Units"));
1845 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_supported_item);
1846
1847 select_present_item = gtk_menu_item_new_with_label(_("Units Present"));
1848 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_present_item);
1849
1850 select_built_improvements_item =
1851 gtk_menu_item_new_with_label(_("Improvements in City"));
1852 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_built_improvements_item);
1853
1854 select_built_wonders_item =
1855 gtk_menu_item_new_with_label(_("Wonders in City"));
1856 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_built_wonders_item);
1857
1858
1859 item = gtk_separator_menu_item_new();
1860 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1861
1862
1863 select_units_item =
1864 gtk_menu_item_new_with_label(_("Available Units"));
1865 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_units_item);
1866 select_improvements_item =
1867 gtk_menu_item_new_with_label(_("Available Improvements"));
1868 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_improvements_item);
1869 select_wonders_item =
1870 gtk_menu_item_new_with_label(_("Available Wonders"));
1871 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_wonders_item);
1872 select_cma_item =
1873 gtk_menu_item_new_with_label(_("Citizen Governor"));
1874 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_cma_item);
1875 }
1876
1877 /****************************************************************
1878 Returns whether city is building given target
1879 *****************************************************************/
city_building_impr_or_unit(const struct city * pcity,const struct universal * target)1880 static bool city_building_impr_or_unit(const struct city *pcity,
1881 const struct universal *target)
1882 {
1883 return are_universals_equal(&pcity->production, target);
1884 }
1885
1886 /****************************************************************
1887 Popup select menu
1888 *****************************************************************/
popup_select_menu(GtkMenuShell * menu,gpointer data)1889 static void popup_select_menu(GtkMenuShell *menu, gpointer data)
1890 {
1891 int n;
1892
1893 if (select_menu_cached)
1894 return;
1895
1896 n = gtk_tree_selection_count_selected_rows(city_selection);
1897 gtk_widget_set_sensitive(select_island_item, (n > 0));
1898
1899 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bunit_item),
1900 TRUE, FALSE, CO_NONE,
1901 city_building_impr_or_unit,
1902 G_CALLBACK(select_impr_or_unit_callback), -1);
1903 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bimprovement_item),
1904 FALSE, FALSE, CO_NONE,
1905 city_building_impr_or_unit,
1906 G_CALLBACK(select_impr_or_unit_callback), -1);
1907 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bwonder_item),
1908 FALSE, TRUE, CO_NONE,
1909 city_building_impr_or_unit,
1910 G_CALLBACK(select_impr_or_unit_callback), -1);
1911
1912 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_supported_item),
1913 TRUE, FALSE, CO_NONE,
1914 city_unit_supported,
1915 G_CALLBACK(select_impr_or_unit_callback), -1);
1916 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_present_item),
1917 TRUE, FALSE, CO_NONE,
1918 city_unit_present,
1919 G_CALLBACK(select_impr_or_unit_callback), -1);
1920 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_improvements_item),
1921 FALSE, FALSE, CO_NONE,
1922 city_building_present,
1923 G_CALLBACK(select_impr_or_unit_callback), -1);
1924 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_wonders_item),
1925 FALSE, TRUE, CO_NONE,
1926 city_building_present,
1927 G_CALLBACK(select_impr_or_unit_callback), -1);
1928
1929 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_improvements_item),
1930 FALSE, FALSE, CO_NONE,
1931 can_city_build_now,
1932 G_CALLBACK(select_impr_or_unit_callback), -1);
1933 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_units_item),
1934 TRUE, FALSE, CO_NONE,
1935 can_city_build_now,
1936 G_CALLBACK(select_impr_or_unit_callback), -1);
1937 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_wonders_item),
1938 FALSE, TRUE, CO_NONE,
1939 can_city_build_now,
1940 G_CALLBACK(select_impr_or_unit_callback), -1);
1941 append_cma_to_menu_item(GTK_MENU_ITEM(select_cma_item), FALSE);
1942
1943 select_menu_cached = TRUE;
1944 }
1945
1946 /***************************************************************************
1947 Update the value displayed by the "total buy cost" label in the city
1948 report, or make it blank if nothing can be bought.
1949 ***************************************************************************/
update_total_buy_cost(void)1950 static void update_total_buy_cost(void)
1951 {
1952 GtkWidget *label, *view;
1953 GList *rows, *p;
1954 GtkTreeModel *model;
1955 GtkTreeSelection *sel;
1956 GtkTreePath *path;
1957 GtkTreeIter iter;
1958 struct city *pcity;
1959 int total = 0;
1960
1961 view = city_view;
1962 label = city_total_buy_cost_label;
1963
1964 if (!view || !label) {
1965 return;
1966 }
1967
1968 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1969 rows = gtk_tree_selection_get_selected_rows(sel, &model);
1970
1971 for (p = rows; p != NULL; p = p->next) {
1972 path = p->data;
1973 if (gtk_tree_model_get_iter(model, &iter, path)) {
1974 if ((pcity = city_model_get(model, &iter))) {
1975 total += city_production_buy_gold_cost(pcity);
1976 }
1977 }
1978 gtk_tree_path_free(path);
1979 }
1980 g_list_free(rows);
1981
1982 if (total > 0) {
1983 gchar *buf = g_strdup_printf(_("Total Buy Cost: %d"), total);
1984 gtk_label_set_text(GTK_LABEL(label), buf);
1985 g_free(buf);
1986 } else {
1987 gtk_label_set_text(GTK_LABEL(label), NULL);
1988 }
1989 }
1990
1991 /***************************************************************************
1992 Update city report button sensitivity and total buy cost label when the
1993 user makes a change in the selection of cities.
1994 ***************************************************************************/
city_selection_changed_callback(GtkTreeSelection * selection)1995 static void city_selection_changed_callback(GtkTreeSelection *selection)
1996 {
1997 int n;
1998 bool obs_may, plr_may;
1999
2000 n = gtk_tree_selection_count_selected_rows(selection);
2001 obs_may = n > 0;
2002 plr_may = obs_may && can_client_issue_orders();
2003
2004 gtk_widget_set_sensitive(city_production_command, plr_may);
2005 gtk_widget_set_sensitive(city_governor_command, plr_may);
2006 gtk_widget_set_sensitive(city_center_command, obs_may);
2007 gtk_widget_set_sensitive(city_popup_command, obs_may);
2008 gtk_widget_set_sensitive(city_buy_command, plr_may);
2009 if (plr_may) {
2010 recreate_sell_menu();
2011 } else {
2012 gtk_widget_set_sensitive(city_sell_command, FALSE);
2013 }
2014
2015 update_total_buy_cost();
2016 }
2017
2018 /**************************************************************************
2019 Clear the worklist in one selected city in the city report.
2020 **************************************************************************/
clear_worklist_foreach_func(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)2021 static void clear_worklist_foreach_func(GtkTreeModel *model,
2022 GtkTreePath *path,
2023 GtkTreeIter *iter,
2024 gpointer data)
2025 {
2026 struct city *pcity = city_model_get(model, iter);
2027
2028 if (NULL != pcity) {
2029 struct worklist empty;
2030
2031 worklist_init(&empty);
2032 city_set_worklist(pcity, &empty);
2033 }
2034 }
2035
2036 /**************************************************************************
2037 Called when the "clear worklist" menu item is activated.
2038 **************************************************************************/
city_clear_worklist_callback(GtkMenuItem * item,gpointer data)2039 static void city_clear_worklist_callback(GtkMenuItem *item, gpointer data)
2040 {
2041 struct connection *pconn = &client.conn;
2042
2043 fc_assert_ret(city_selection != NULL);
2044
2045 connection_do_buffer(pconn);
2046 gtk_tree_selection_selected_foreach(city_selection,
2047 clear_worklist_foreach_func, NULL);
2048 connection_do_unbuffer(pconn);
2049 }
2050
2051 /****************************************************************
2052 After a selection rectangle is defined, make the cities that
2053 are hilited on the canvas exclusively hilited in the
2054 City List window.
2055 *****************************************************************/
hilite_cities_from_canvas(void)2056 void hilite_cities_from_canvas(void)
2057 {
2058 ITree it;
2059 GtkTreeModel *model;
2060
2061 if (!city_dialog_shell) return;
2062
2063 model = GTK_TREE_MODEL(city_model);
2064
2065 gtk_tree_selection_unselect_all(city_selection);
2066
2067 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
2068 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
2069
2070 if (NULL != pcity && is_city_hilited(pcity)) {
2071 itree_select(city_selection, &it);
2072 }
2073 }
2074 }
2075
2076 /****************************************************************
2077 Toggle a city's hilited status.
2078 *****************************************************************/
toggle_city_hilite(struct city * pcity,bool on_off)2079 void toggle_city_hilite(struct city *pcity, bool on_off)
2080 {
2081 GtkTreeIter iter;
2082
2083 if (NULL == city_dialog_shell) {
2084 return;
2085 }
2086
2087 if (city_model_find(GTK_TREE_MODEL(city_model), &iter, pcity)) {
2088 if (on_off) {
2089 gtk_tree_selection_select_iter(city_selection, &iter);
2090 } else {
2091 gtk_tree_selection_unselect_iter(city_selection, &iter);
2092 }
2093 }
2094 }
2095