Replaced deprecated gtk_menu_popup() calls with modern constructs in gtk3.22-client
[freeciv.git] / client / gui-gtk-3.0 / cityrep.c
blob6ac1a0b3be1d3c6eab9a7fcd1edd5ccaa4e74a1e
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
25 /* utility */
26 #include "fcintl.h"
27 #include "log.h"
28 #include "shared.h"
29 #include "support.h"
31 /* common */
32 #include "city.h"
33 #include "game.h"
34 #include "packets.h"
35 #include "unit.h"
37 /* client/agents */
38 #include "cma_fec.h"
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"
49 /* client/gui-gtk-3.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"
59 #include "cityrep.h"
61 #define NEG_VAL(x) ((x)<0 ? (x) : (-x))
63 /* Some versions of gcc have problems with negative values here (PR#39722). */
64 #define CMA_NONE (10000)
65 #define CMA_CUSTOM (10001)
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. */
73 enum city_operation_type {
74 CO_CHANGE, CO_LAST, CO_NEXT, CO_FIRST, CO_NEXT_TO_LAST, CO_SELL, CO_NONE
77 /******************************************************************/
78 static void create_city_report_dialog(bool make_modal);
80 static void city_activated_callback(GtkTreeView *view, GtkTreePath *path,
81 GtkTreeViewColumn *col, gpointer data);
83 static void city_command_callback(struct gui_dialog *dlg, int response,
84 gpointer data);
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);
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);
98 static struct gui_dialog *city_dialog_shell = NULL;
100 enum {
101 CITY_CENTER = 1, CITY_POPUP, CITY_BUY
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)
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);
116 static void recreate_sell_menu(void);
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;
126 static GtkWidget *change_improvements_item;
127 static GtkWidget *change_units_item;
128 static GtkWidget *change_wonders_item;
130 static GtkWidget *last_improvements_item;
131 static GtkWidget *last_units_item;
132 static GtkWidget *last_wonders_item;
134 static GtkWidget *first_improvements_item;
135 static GtkWidget *first_units_item;
136 static GtkWidget *first_wonders_item;
138 static GtkWidget *next_improvements_item;
139 static GtkWidget *next_units_item;
140 static GtkWidget *next_wonders_item;
142 static GtkWidget *next_to_last_improvements_item;
143 static GtkWidget *next_to_last_units_item;
144 static GtkWidget *next_to_last_wonders_item;
146 static GtkWidget *select_island_item;
148 static GtkWidget *select_bunit_item;
149 static GtkWidget *select_bimprovement_item;
150 static GtkWidget *select_bwonder_item;
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;
157 static GtkWidget *select_improvements_item;
158 static GtkWidget *select_units_item;
159 static GtkWidget *select_wonders_item;
160 static GtkWidget *select_cma_item;
162 static int city_dialog_shell_is_modal;
164 bool select_menu_cached;
166 /****************************************************************
167 Return text line for the column headers for the city report
168 *****************************************************************/
169 static void get_city_table_header(char **text, int n)
171 struct city_report_spec *spec;
172 int i;
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 : "");
181 /****************************************************************************
182 CITY REPORT DIALOG
183 ****************************************************************************/
185 /****************************************************************************
186 Returns a new tree model for the city report.
187 ****************************************************************************/
188 static GtkListStore *city_report_dialog_store_new(void)
190 GType model_types[NUM_CREPORT_COLS + 1];
191 gint i;
193 /* City report data. */
194 for (i = 0; i < NUM_CREPORT_COLS; i++) {
195 model_types[i] = G_TYPE_STRING;
198 /* Specific gtk client data. */
199 model_types[i++] = G_TYPE_INT; /* CRD_COL_CITY_ID */
201 return gtk_list_store_newv(i, model_types);
204 /****************************************************************************
205 Set the values of the iterator.
206 ****************************************************************************/
207 static void city_model_set(GtkListStore *store, GtkTreeIter *iter,
208 struct city *pcity)
210 struct city_report_spec *spec;
211 char buf[64];
212 gint i;
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);
220 gtk_list_store_set(store, iter, CRD_COL_CITY_ID, pcity->id, -1);
223 /****************************************************************************
224 Set the values of the iterator.
225 ****************************************************************************/
226 static struct city *city_model_get(GtkTreeModel *model, GtkTreeIter *iter)
228 struct city *pcity;
229 int id;
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);
239 /****************************************************************************
240 Return TRUE if 'iter' has been set to the city row.
241 ****************************************************************************/
242 static gboolean city_model_find(GtkTreeModel *model, GtkTreeIter *iter,
243 const struct city *pcity)
245 const int searched = pcity->id;
246 int id;
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;
254 } while (gtk_tree_model_iter_next(model, iter));
256 return FALSE;
259 /****************************************************************************
260 Fill the model with the current configuration.
261 ****************************************************************************/
262 static void city_model_fill(GtkListStore *store,
263 GtkTreeSelection *selection, GHashTable *select)
265 GtkTreeIter iter;
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);
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);
285 } cities_iterate_end;
289 /****************************************************************
290 Popup the city report dialog, and optionally raise it.
291 ****************************************************************/
292 void city_report_dialog_popup(bool raise)
294 if(!city_dialog_shell) {
295 city_dialog_shell_is_modal = FALSE;
297 create_city_report_dialog(FALSE);
299 select_menu_cached = FALSE;
302 gui_dialog_present(city_dialog_shell);
303 hilite_cities_from_canvas();
304 if (raise) {
305 gui_dialog_raise(city_dialog_shell);
309 /****************************************************************
310 Closes the city report dialog.
311 ****************************************************************/
312 void city_report_dialog_popdown(void)
314 if (city_dialog_shell) {
315 gui_dialog_destroy(city_dialog_shell);
319 /****************************************************************
320 Make submenu listing possible build targets
321 *****************************************************************/
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)
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];
338 GtkSizeGroup *group[3];
339 const char *markup[3] = {
340 "weight=\"bold\"",
345 menu = gtk_menu_new();
346 gtk_menu_item_set_submenu(parent_item, menu);
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;
355 selected = g_ptr_array_sized_new(size);
357 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
358 struct city *pcity;
360 if (!itree_is_selected(city_selection, &it)
361 || !(pcity = city_model_get(model, TREE_ITER_PTR(it)))) {
362 continue;
365 g_ptr_array_add(selected, pcity);
366 num_selected++;
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);
380 name_and_sort_items(targets, targets_used, items,
381 city_operation != CO_NONE, NULL);
383 for (i = 0; i < 4; i++) {
384 row[i] = buf[i];
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));
391 for (i = 0; i < 3; i++) {
392 group[i] = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
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];
400 get_city_dialog_production_row(row, sizeof(buf[0]), &target, NULL);
402 menu_item = gtk_menu_item_new();
403 hbox = gtk_grid_new();
404 gtk_grid_set_column_spacing(GTK_GRID(hbox), 18);
405 gtk_container_add(GTK_CONTAINER(menu_item), hbox);
407 for (i = 0; i < 3; i++) {
408 if (row[i][0] == '\0') {
409 continue;
412 if (city_operation == CO_SELL && i != 0) {
413 continue;
416 fc_snprintf(txt, ARRAY_SIZE(txt), "<span %s>%s</span>",
417 markup[i], row[i]);
419 label = gtk_label_new(NULL);
420 gtk_label_set_markup(GTK_LABEL(label), txt);
422 switch (i) {
423 case 0:
424 gtk_widget_set_halign(label, GTK_ALIGN_START);
425 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
426 break;
427 case 2:
428 gtk_widget_set_halign(label, GTK_ALIGN_END);
429 gtk_widget_set_valign(label, GTK_ALIGN_CENTER);
430 break;
431 default:
432 break;
435 gtk_container_add(GTK_CONTAINER(hbox), label);
436 gtk_size_group_add_widget(group[i], label);
439 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
440 g_signal_connect(menu_item, "activate", callback,
441 GINT_TO_POINTER(cid_encode(target)));
444 for (i = 0; i < 3; i++) {
445 g_object_unref(group[i]);
448 gtk_widget_show_all(menu);
450 gtk_widget_set_sensitive(GTK_WIDGET(parent_item), (targets_used > 0));
453 /****************************************************************************
454 Change the production of one single selected city.
455 ****************************************************************************/
456 static void impr_or_unit_iterate(GtkTreeModel *model, GtkTreePath *path,
457 GtkTreeIter *iter, gpointer data)
459 struct universal target = cid_decode(GPOINTER_TO_INT(data));
460 struct city *pcity = city_model_get(model, iter);
462 if (NULL != pcity) {
463 city_change_production(pcity, &target);
467 /****************************************************************************
468 Called by select_impr_or_unit_callback for each city that is selected in
469 the city list dialog to have a object appended to the worklist. Sends a
470 packet adding the item to the end of the worklist.
471 ****************************************************************************/
472 static void worklist_last_impr_or_unit_iterate(GtkTreeModel *model,
473 GtkTreePath *path,
474 GtkTreeIter *iter,
475 gpointer data)
477 struct universal target = cid_decode(GPOINTER_TO_INT(data));
478 struct city *pcity = city_model_get(model, iter);
480 if (NULL != pcity) {
481 (void) city_queue_insert(pcity, -1, &target);
483 /* perhaps should warn the user if not successful? */
486 /****************************************************************************
487 Called by select_impr_or_unit_callback for each city that is selected in
488 the city list dialog to have a object inserted first to the worklist.
489 Sends a packet adding the current production to the first place after the
490 current production of the worklist. Then changes the production to the
491 requested item.
492 ****************************************************************************/
493 static void worklist_first_impr_or_unit_iterate(GtkTreeModel *model,
494 GtkTreePath *path,
495 GtkTreeIter *iter,
496 gpointer data)
498 struct universal target = cid_decode(GPOINTER_TO_INT(data));
499 struct city *pcity = city_model_get(model, iter);
501 if (NULL != pcity) {
502 (void) city_queue_insert(pcity, 0, &target);
504 /* perhaps should warn the user if not successful? */
507 /****************************************************************************
508 Called by select_impr_or_unit_callback for each city that is selected in
509 the city list dialog to have a object added next to the worklist. Sends a
510 packet adding the item to the first place after the current production of
511 the worklist.
512 ****************************************************************************/
513 static void worklist_next_impr_or_unit_iterate(GtkTreeModel *model,
514 GtkTreePath *path,
515 GtkTreeIter *iter,
516 gpointer data)
518 struct universal target = cid_decode(GPOINTER_TO_INT(data));
519 struct city *pcity = city_model_get(model, iter);
521 if (NULL != pcity) {
522 (void) city_queue_insert(pcity, 1, &target);
524 /* perhaps should warn the user if not successful? */
527 /****************************************************************************
528 Called by select_impr_or_unit_callback for each city that is selected in
529 the city list dialog to have an object added before the last position in
530 the worklist.
531 ****************************************************************************/
532 static void worklist_next_to_last_impr_or_unit_iterate(GtkTreeModel *model,
533 GtkTreePath *path,
534 GtkTreeIter *iter,
535 gpointer data)
537 struct universal target = cid_decode(GPOINTER_TO_INT(data));
538 struct city *pcity = city_model_get(model, iter);
540 if (NULL != pcity) {
541 city_queue_insert(pcity, worklist_length(&pcity->worklist), &target);
545 /****************************************************************************
546 Iterate the cities going to sell.
547 ****************************************************************************/
548 static void sell_impr_iterate(GtkTreeModel *model, GtkTreePath *path,
549 GtkTreeIter *iter, gpointer data)
551 struct sell_data *sd = (struct sell_data *) data;
552 struct city *pcity = city_model_get(model, iter);
554 if (NULL != pcity
555 && !pcity->did_sell
556 && city_has_building(pcity, sd->target)) {
557 sd->count++;
558 sd->gold += impr_sell_gold(sd->target);
559 city_sell_improvement(pcity, improvement_number(sd->target));
563 /****************************************************************************
564 Some build target, either improvement or unit, has been selected from
565 some menu.
566 ****************************************************************************/
567 static void select_impr_or_unit_callback(GtkWidget *wdg, gpointer data)
569 struct universal target = cid_decode(GPOINTER_TO_INT(data));
570 GObject *parent = G_OBJECT(gtk_widget_get_parent(wdg));
571 TestCityFunc test_func = g_object_get_data(parent, "freeciv_test_func");
572 enum city_operation_type city_operation =
573 GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_city_operation"));
575 /* if this is not a city operation: */
576 if (city_operation == CO_NONE) {
577 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
578 ITree it;
580 gtk_tree_selection_unselect_all(city_selection);
581 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
582 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
584 if (NULL != pcity && test_func(pcity, &target)) {
585 itree_select(city_selection, &it);
588 } else {
589 GtkTreeSelectionForeachFunc foreach_func;
590 connection_do_buffer(&client.conn);
591 switch (city_operation) {
592 case CO_LAST:
593 gtk_tree_selection_selected_foreach(city_selection,
594 worklist_last_impr_or_unit_iterate,
595 GINT_TO_POINTER(cid_encode(target)));
596 break;
597 case CO_CHANGE:
598 gtk_tree_selection_selected_foreach(city_selection,
599 impr_or_unit_iterate,
600 GINT_TO_POINTER(cid_encode(target)));
601 break;
602 case CO_FIRST:
603 gtk_tree_selection_selected_foreach(city_selection,
604 worklist_first_impr_or_unit_iterate,
605 GINT_TO_POINTER(cid_encode(target)));
606 break;
607 case CO_NEXT:
608 gtk_tree_selection_selected_foreach(city_selection,
609 worklist_next_impr_or_unit_iterate,
610 GINT_TO_POINTER(cid_encode(target)));
611 break;
612 case CO_NEXT_TO_LAST:
613 foreach_func = worklist_next_to_last_impr_or_unit_iterate;
614 gtk_tree_selection_selected_foreach(city_selection, foreach_func,
615 GINT_TO_POINTER(cid_encode(target)));
616 break;
617 case CO_SELL:
618 fc_assert_action(target.kind == VUT_IMPROVEMENT, break);
620 struct impr_type *building = target.value.building;
621 struct sell_data sd = { 0, 0, building };
622 GtkWidget *w;
623 gint res;
624 gchar *buf;
625 const char *imprname = improvement_name_translation(building);
627 /* Ask confirmation */
628 buf = g_strdup_printf(_("Are you sure you want to sell those %s?"), imprname);
629 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
630 GTK_MESSAGE_QUESTION,
631 GTK_BUTTONS_YES_NO, "%s", buf);
632 g_free(buf);
633 res = gtk_dialog_run(GTK_DIALOG(w)); /* Synchron. */
634 gtk_widget_destroy(w);
635 if (res == GTK_RESPONSE_NO) {
636 break;
639 gtk_tree_selection_selected_foreach(city_selection,
640 sell_impr_iterate, &sd);
641 if (sd.count > 0) {
642 /* FIXME: plurality of sd.count is ignored! */
643 /* TRANS: "Sold 3 Harbor for 90 gold." (Pluralisation is in gold --
644 * second %d -- not in buildings.) */
645 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
646 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
647 PL_("Sold %d %s for %d gold.",
648 "Sold %d %s for %d gold.",
649 sd.gold),
650 sd.count, imprname, sd.gold);
651 } else {
652 w = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
653 GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
654 _("No %s could be sold."),
655 imprname);
658 g_signal_connect(w, "response",
659 G_CALLBACK(gtk_widget_destroy), NULL);
660 gtk_window_present(GTK_WINDOW(w)); /* Asynchron. */
662 break;
663 case CO_NONE:
664 break;
666 connection_do_unbuffer(&client.conn);
670 /****************************************************************************
671 CMA callback.
672 ****************************************************************************/
673 static void cma_iterate(GtkTreeModel *model, GtkTreePath *path,
674 GtkTreeIter *iter, gpointer data)
676 struct city *pcity = city_model_get(model, iter);
677 int idx = GPOINTER_TO_INT(data);
679 if (NULL != pcity) {
680 if (CMA_NONE == idx) {
681 cma_release_city(pcity);
682 } else {
683 cma_put_city_under_agent(pcity, cmafec_preset_get_parameter(idx));
685 refresh_city_dialog(pcity);
689 /****************************************************************
690 Called when one clicks on an CMA item to make a selection or to
691 change a selection's preset.
692 *****************************************************************/
693 static void select_cma_callback(GtkWidget * w, gpointer data)
695 int idx = GPOINTER_TO_INT(data);
696 GObject *parent = G_OBJECT(gtk_widget_get_parent(w));
697 bool change_cma =
698 GPOINTER_TO_INT(g_object_get_data(parent, "freeciv_change_cma"));
699 struct cm_parameter parameter;
701 /* If this is not the change button but the select cities button. */
702 if (!change_cma) {
703 ITree it;
704 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
706 gtk_tree_selection_unselect_all(city_selection);
707 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
708 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
709 int controlled;
710 bool select;
712 if (NULL == pcity) {
713 continue;
715 controlled = cma_is_city_under_agent(pcity, &parameter);
716 select = FALSE;
718 if (idx == CMA_NONE) {
719 /* CMA_NONE selects not-controlled, all others require controlled */
720 if (!controlled) {
721 select = TRUE;
723 } else if (controlled) {
724 if (idx == CMA_CUSTOM) {
725 if (cmafec_preset_get_index_of_parameter(&parameter) == -1) {
726 select = TRUE;
728 } else if (cm_are_parameter_equal(&parameter,
729 cmafec_preset_get_parameter(idx))) {
730 select = TRUE;
734 if (select) {
735 itree_select(city_selection, &it);
738 } else {
739 gtk_tree_selection_selected_foreach(city_selection,
740 cma_iterate, GINT_TO_POINTER(idx));
744 /****************************************************************
745 Create the cma entries in the change menu and the select menu. The
746 indices CMA_NONE and CMA_CUSTOM are special.
747 CMA_NONE signifies a preset of "none" and CMA_CUSTOM a
748 "custom" preset.
749 *****************************************************************/
750 static void append_cma_to_menu_item(GtkMenuItem *parent_item, bool change_cma)
752 GtkWidget *menu;
753 int i;
754 struct cm_parameter parameter;
755 GtkWidget *w;
757 w = gtk_menu_item_get_submenu(parent_item);
758 if (w != NULL && gtk_widget_get_visible(w)) {
759 return;
762 if (!can_client_issue_orders()) {
763 gtk_menu_item_set_submenu(parent_item, NULL);
764 return;
766 menu = gtk_menu_new();
767 gtk_menu_item_set_submenu(parent_item, menu);
769 if (change_cma) {
770 w = gtk_menu_item_new_with_label(_("none"));
771 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
772 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
773 GINT_TO_POINTER(CMA_NONE));
774 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(CMA_NONE)) == CMA_NONE);
776 for (i = 0; i < cmafec_preset_num(); i++) {
777 w = gtk_menu_item_new_with_label(cmafec_preset_get_descr(i));
778 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
779 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
780 GINT_TO_POINTER(i));
781 fc_assert(GPOINTER_TO_INT(GINT_TO_POINTER(i)) == i);
783 } else {
784 /* search for a "none" */
785 int found;
787 found = 0;
788 city_list_iterate(client.conn.playing->cities, pcity) {
789 if (!cma_is_city_under_agent(pcity, NULL)) {
790 found = 1;
791 break;
793 } city_list_iterate_end;
795 if (found) {
796 w = gtk_menu_item_new_with_label(_("none"));
797 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
798 g_signal_connect(w, "activate", G_CALLBACK(select_cma_callback),
799 GINT_TO_POINTER(CMA_NONE));
803 * Search for a city that's under custom (not preset) agent. Might
804 * take a lonnggg time.
806 found = 0;
807 city_list_iterate(client.conn.playing->cities, pcity) {
808 if (cma_is_city_under_agent(pcity, &parameter) &&
809 cmafec_preset_get_index_of_parameter(&parameter) == -1) {
810 found = 1;
811 break;
813 } city_list_iterate_end;
815 if (found) {
816 /* we found city that's under agent but not a preset */
817 w = gtk_menu_item_new_with_label(_("custom"));
819 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
820 g_signal_connect(w, "activate",
821 G_CALLBACK(select_cma_callback), GINT_TO_POINTER(CMA_CUSTOM));
824 /* only fill in presets that are being used. */
825 for (i = 0; i < cmafec_preset_num(); i++) {
826 found = 0;
827 city_list_iterate(client.conn.playing->cities, pcity) {
828 if (cma_is_city_under_agent(pcity, &parameter) &&
829 cm_are_parameter_equal(&parameter,
830 cmafec_preset_get_parameter(i))) {
831 found = 1;
832 break;
834 } city_list_iterate_end;
835 if (found) {
836 w = gtk_menu_item_new_with_label(cmafec_preset_get_descr(i));
838 gtk_menu_shell_append(GTK_MENU_SHELL(menu), w);
839 g_signal_connect(w, "activate",
840 G_CALLBACK(select_cma_callback), GINT_TO_POINTER(i));
845 g_object_set_data(G_OBJECT(menu), "freeciv_change_cma",
846 GINT_TO_POINTER(change_cma));
847 gtk_widget_show_all(menu);
850 /****************************************************************************
851 Helper function to append a worklist to the current work list of one city
852 in the city report. This function is called over all selected rows in the
853 list view.
854 ****************************************************************************/
855 static void append_worklist_foreach(GtkTreeModel *model, GtkTreePath *path,
856 GtkTreeIter *iter, gpointer data)
858 const struct worklist *pwl = data;
859 struct city *pcity = city_model_get(model, iter);
861 fc_assert_ret(pwl != NULL);
863 if (NULL != pcity) {
864 city_queue_insert_worklist(pcity, -1, pwl);
868 /**************************************************************************
869 Menu item callback to append the global worklist associated with this
870 item to the worklists of all selected cities. The worklist pointer is
871 passed in 'data'.
872 **************************************************************************/
873 static void append_worklist_callback(GtkMenuItem *menuitem, gpointer data)
875 struct global_worklist *pgwl =
876 global_worklist_by_id(GPOINTER_TO_INT(data));
878 fc_assert_ret(city_selection != NULL);
880 if (!pgwl) {
881 /* Maybe removed by an other way, not an error. */
882 return;
885 gtk_tree_selection_selected_foreach(city_selection,
886 append_worklist_foreach,
887 (gpointer) global_worklist_get(pgwl));
890 /****************************************************************************
891 Helper function to set a worklist for one city in the city report. This
892 function is called over all selected rows in the list view.
893 ****************************************************************************/
894 static void set_worklist_foreach(GtkTreeModel *model, GtkTreePath *path,
895 GtkTreeIter *iter, gpointer data)
897 const struct worklist *pwl = data;
898 struct city *pcity = city_model_get(model, iter);
900 fc_assert_ret(pwl != NULL);
902 if (NULL != pcity) {
903 city_set_queue(pcity, pwl);
907 /**************************************************************************
908 Menu item callback to set a city's worklist to the global worklist
909 associated with this menu item. The worklist pointer is passed in 'data'.
910 **************************************************************************/
911 static void set_worklist_callback(GtkMenuItem *menuitem, gpointer data)
913 struct global_worklist *pgwl =
914 global_worklist_by_id(GPOINTER_TO_INT(data));
916 fc_assert_ret(city_selection != NULL);
917 gtk_tree_selection_selected_foreach(city_selection, set_worklist_foreach,
918 (gpointer) global_worklist_get(pgwl));
920 if (!pgwl) {
921 /* Maybe removed by an other way, not an error. */
922 return;
925 gtk_tree_selection_selected_foreach(city_selection,
926 set_worklist_foreach,
927 (gpointer) global_worklist_get(pgwl));
930 /**************************************************************************
931 Empty and refill the submenu of the menu item passed as 'data'. The menu
932 will be filled with menu items corresponding to the global worklists.
933 **************************************************************************/
934 static void production_menu_shown(GtkWidget *widget, gpointer data)
936 GtkWidget *menu, *item;
937 GtkMenuItem *parent_item;
938 GCallback callback;
939 int count = 0;
941 parent_item = data;
942 fc_assert_ret(parent_item != NULL);
943 fc_assert_ret(GTK_IS_MENU_ITEM(parent_item));
945 callback = g_object_get_data(G_OBJECT(parent_item), "item_callback");
946 fc_assert_ret(callback != NULL);
948 menu = gtk_menu_item_get_submenu(parent_item);
949 if (menu != NULL && gtk_widget_get_visible(menu)) {
950 gtk_menu_shell_deactivate(GTK_MENU_SHELL(menu));
953 if (menu == NULL) {
954 menu = gtk_menu_new();
955 gtk_menu_item_set_submenu(parent_item, menu);
958 if (!can_client_issue_orders()) {
959 return;
962 gtk_container_forall(GTK_CONTAINER(menu),
963 (GtkCallback) gtk_widget_destroy, NULL);
965 global_worklists_iterate(pgwl) {
966 item = gtk_menu_item_new_with_label(global_worklist_name(pgwl));
967 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
968 g_signal_connect(item, "activate", callback,
969 GINT_TO_POINTER(global_worklist_id(pgwl)));
970 count++;
971 } global_worklists_iterate_end;
973 if (count == 0) {
974 item = gtk_menu_item_new_with_label(_("(no worklists defined)"));
975 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
978 gtk_widget_show_all(menu);
981 /****************************************************************
982 Update city report views
983 *****************************************************************/
984 static void city_report_update_views(void)
986 struct city_report_spec *spec;
987 GtkTreeView *view;
988 GtkTreeViewColumn *col;
989 GList *columns, *p;
991 view = GTK_TREE_VIEW(city_view);
992 fc_assert_ret(view != NULL);
994 columns = gtk_tree_view_get_columns(view);
996 for (p = columns; p != NULL; p = p->next) {
997 col = p->data;
998 spec = g_object_get_data(G_OBJECT(col), "city_report_spec");
999 gtk_tree_view_column_set_visible(col, spec->show);
1002 g_list_free(columns);
1005 /****************************************************************
1006 User has toggled some column viewing option
1007 *****************************************************************/
1008 static void toggle_view(GtkCheckMenuItem *item, gpointer data)
1010 struct city_report_spec *spec = data;
1012 spec->show ^= 1;
1013 city_report_update_views();
1016 /****************************************************************
1017 Create view menu for city report menubar.
1018 *****************************************************************/
1019 static void update_view_menu(GtkWidget *show_item)
1021 GtkWidget *menu, *item;
1022 struct city_report_spec *spec;
1023 int i;
1025 menu = gtk_menu_new();
1026 for(i=0, spec=city_report_specs+i; i<NUM_CREPORT_COLS; i++, spec++) {
1027 item = gtk_check_menu_item_new_with_label(spec->explanation);
1028 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1029 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), spec->show);
1030 g_signal_connect(item, "toggled", G_CALLBACK(toggle_view), (gpointer)spec);
1032 gtk_menu_item_set_submenu(GTK_MENU_ITEM(show_item), menu);
1035 /****************************************************************
1036 Create menubar for city report
1037 *****************************************************************/
1038 static GtkWidget *create_city_report_menubar(void)
1040 GtkWidget *vbox, *sep, *menubar, *menu, *item;
1042 vbox = gtk_grid_new();
1043 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
1044 GTK_ORIENTATION_VERTICAL);
1045 sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
1046 gtk_container_add(GTK_CONTAINER(vbox), sep);
1048 menubar = gtk_aux_menu_bar_new();
1049 gtk_container_add(GTK_CONTAINER(vbox), menubar);
1051 item = gtk_menu_item_new_with_mnemonic(_("_Production"));
1052 city_production_command = item;
1053 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1055 menu = gtk_menu_new();
1056 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1058 item = gtk_menu_item_new_with_mnemonic(_("Chan_ge"));
1059 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1060 create_change_menu(item);
1062 item = gtk_menu_item_new_with_mnemonic(_("Add _First"));
1063 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1064 create_first_menu(item);
1066 item = gtk_menu_item_new_with_mnemonic(_("Add _Next"));
1067 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1068 create_next_menu(item);
1070 item = gtk_menu_item_new_with_mnemonic(_("Add _2nd Last"));
1071 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1072 create_next_to_last_menu(item);
1074 item = gtk_menu_item_new_with_mnemonic(_("Add _Last"));
1075 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1076 create_last_menu(item);
1078 item = gtk_separator_menu_item_new();
1079 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1081 item = gtk_menu_item_new_with_label(_("Set Worklist"));
1082 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1083 g_object_set_data(G_OBJECT(item), "item_callback",
1084 set_worklist_callback);
1085 g_signal_connect(menu, "show", G_CALLBACK(production_menu_shown), item);
1087 item = gtk_menu_item_new_with_label(_("Append Worklist"));
1088 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1089 g_object_set_data(G_OBJECT(item), "item_callback",
1090 append_worklist_callback);
1091 g_signal_connect(menu, "show", G_CALLBACK(production_menu_shown), item);
1093 item = gtk_menu_item_new_with_mnemonic(_("Clear _Worklist"));
1094 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1095 g_signal_connect(item, "activate",
1096 G_CALLBACK(city_clear_worklist_callback), NULL);
1098 item = gtk_menu_item_new_with_mnemonic(_("Gover_nor"));
1099 city_governor_command = item;
1100 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1101 append_cma_to_menu_item(GTK_MENU_ITEM(item), TRUE);
1103 item = gtk_menu_item_new_with_mnemonic(_("S_ell"));
1104 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1105 city_sell_command = item;
1106 create_sell_menu(item);
1108 item = gtk_menu_item_new_with_mnemonic(_("_Select"));
1109 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1110 create_select_menu(item);
1112 item = gtk_menu_item_new_with_mnemonic(_("_Display"));
1113 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1114 update_view_menu(item);
1115 return vbox;
1118 /****************************************************************************
1119 Sort callback.
1120 ****************************************************************************/
1121 static gint cityrep_sort_func(GtkTreeModel *model, GtkTreeIter *a,
1122 GtkTreeIter *b, gpointer data)
1124 gint col = GPOINTER_TO_INT(data);
1125 const gchar *str1, *str2;
1127 gtk_tree_model_get(model, a, col, &str1, -1);
1128 gtk_tree_model_get(model, b, col, &str2, -1);
1130 return cityrepfield_compare(str1, str2);
1133 /****************************************************************
1134 Create city report dialog.
1135 *****************************************************************/
1136 static void create_city_report_dialog(bool make_modal)
1138 static char **titles;
1139 static char (*buf)[128];
1140 struct city_report_spec *spec;
1142 GtkWidget *w, *sw, *menubar;
1143 int i;
1145 gui_dialog_new(&city_dialog_shell, GTK_NOTEBOOK(top_notebook), NULL, TRUE);
1146 gui_dialog_set_title(city_dialog_shell, _("Cities"));
1148 gui_dialog_set_default_size(city_dialog_shell, -1, 420);
1150 gui_dialog_response_set_callback(city_dialog_shell,
1151 city_command_callback);
1153 /* menubar */
1154 menubar = create_city_report_menubar();
1155 gui_dialog_add_widget(city_dialog_shell, menubar);
1157 /* buttons */
1158 city_total_buy_cost_label = gtk_label_new(NULL);
1159 gtk_widget_set_hexpand(city_total_buy_cost_label, TRUE);
1160 gtk_label_set_ellipsize(GTK_LABEL(city_total_buy_cost_label),
1161 PANGO_ELLIPSIZE_START);
1162 gtk_container_add(GTK_CONTAINER(city_dialog_shell->action_area),
1163 city_total_buy_cost_label);
1165 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_EXECUTE,
1166 _("_Buy"), CITY_BUY);
1167 city_buy_command = w;
1169 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_ZOOM_IN,
1170 _("_Inspect"), CITY_POPUP);
1171 city_popup_command = w;
1173 w = gui_dialog_add_stockbutton(city_dialog_shell, GTK_STOCK_ZOOM_FIT,
1174 _("Cen_ter"), CITY_CENTER);
1175 city_center_command = w;
1177 gui_dialog_set_default_response(city_dialog_shell,
1178 GTK_RESPONSE_CLOSE);
1180 /* tree view */
1181 buf = fc_realloc(buf, NUM_CREPORT_COLS * sizeof(buf[0]));
1182 titles = fc_realloc(titles, NUM_CREPORT_COLS * sizeof(titles[0]));
1183 for (i = 0; i < NUM_CREPORT_COLS; i++) {
1184 titles[i] = buf[i];
1186 get_city_table_header(titles, sizeof(buf[0]));
1188 city_model = city_report_dialog_store_new();
1190 city_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(city_model));
1191 gtk_widget_set_hexpand(city_view, TRUE);
1192 gtk_widget_set_vexpand(city_view, TRUE);
1193 g_object_unref(city_model);
1194 gtk_widget_set_name(city_view, "small_font");
1195 g_signal_connect(city_view, "row_activated",
1196 G_CALLBACK(city_activated_callback), NULL);
1197 city_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(city_view));
1198 gtk_tree_selection_set_mode(city_selection, GTK_SELECTION_MULTIPLE);
1199 g_signal_connect(city_selection, "changed",
1200 G_CALLBACK(city_selection_changed_callback), NULL);
1202 for (i = 0, spec = city_report_specs; i < NUM_CREPORT_COLS; i++, spec++) {
1203 GtkWidget *header;
1204 GtkCellRenderer *renderer;
1205 GtkTreeViewColumn *col;
1207 renderer = gtk_cell_renderer_text_new();
1208 col = gtk_tree_view_column_new_with_attributes(NULL, renderer,
1209 "text", i, NULL);
1210 header = gtk_label_new(titles[i]);
1211 gtk_widget_set_tooltip_text(header, spec->explanation);
1212 gtk_widget_show(header);
1213 gtk_tree_view_column_set_widget(col, header);
1214 gtk_tree_view_column_set_visible(col, spec->show);
1215 gtk_tree_view_column_set_sort_column_id(col, i);
1216 gtk_tree_view_column_set_reorderable(col, TRUE);
1217 g_object_set_data(G_OBJECT(col), "city_report_spec", spec);
1218 gtk_tree_view_append_column(GTK_TREE_VIEW(city_view), col);
1219 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(city_model), i,
1220 cityrep_sort_func, GINT_TO_POINTER(i),
1221 NULL);
1224 sw = gtk_scrolled_window_new(NULL, NULL);
1225 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1226 GTK_SHADOW_ETCHED_IN);
1227 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1228 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1229 gtk_container_add(GTK_CONTAINER(sw), city_view);
1231 gtk_container_add(GTK_CONTAINER(city_dialog_shell->vbox), sw);
1233 city_model_fill(city_model, NULL, NULL);
1234 gui_dialog_show_all(city_dialog_shell);
1236 city_selection_changed_callback(city_selection);
1239 /****************************************************************
1240 User has chosen to select all cities
1241 *****************************************************************/
1242 static void city_select_all_callback(GtkMenuItem *item, gpointer data)
1244 gtk_tree_selection_select_all(city_selection);
1247 /****************************************************************
1248 User has chosen to unselect all cities
1249 *****************************************************************/
1250 static void city_unselect_all_callback(GtkMenuItem *item, gpointer data)
1252 gtk_tree_selection_unselect_all(city_selection);
1255 /****************************************************************
1256 User has chosen to invert selection
1257 *****************************************************************/
1258 static void city_invert_selection_callback(GtkMenuItem *item, gpointer data)
1260 ITree it;
1261 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1263 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1264 if (itree_is_selected(city_selection, &it)) {
1265 itree_unselect(city_selection, &it);
1266 } else {
1267 itree_select(city_selection, &it);
1272 /****************************************************************
1273 User has chosen to select coastal cities
1274 *****************************************************************/
1275 static void city_select_coastal_callback(GtkMenuItem *item, gpointer data)
1277 ITree it;
1278 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1280 gtk_tree_selection_unselect_all(city_selection);
1282 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1283 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1285 if (NULL != pcity && is_terrain_class_near_tile(pcity->tile, TC_OCEAN)) {
1286 itree_select(city_selection, &it);
1291 /****************************************************************************
1292 Select all cities on the same continent.
1293 ****************************************************************************/
1294 static void same_island_iterate(GtkTreeModel *model, GtkTreePath *path,
1295 GtkTreeIter *iter, gpointer data)
1297 struct city *selected_pcity = city_model_get(model, iter);
1298 ITree it;
1300 if (NULL == selected_pcity) {
1301 return;
1304 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1305 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1307 if (NULL != pcity
1308 && (tile_continent(pcity->tile)
1309 == tile_continent(selected_pcity->tile))) {
1310 itree_select(city_selection, &it);
1315 /****************************************************************
1316 User has chosen to select all cities on same island
1317 *****************************************************************/
1318 static void city_select_same_island_callback(GtkMenuItem *item, gpointer data)
1320 gtk_tree_selection_selected_foreach(city_selection,same_island_iterate,NULL);
1323 /****************************************************************
1324 User has chosen to select cities with certain target in production
1325 *****************************************************************/
1326 static void city_select_building_callback(GtkMenuItem *item, gpointer data)
1328 enum production_class_type which = GPOINTER_TO_INT(data);
1329 ITree it;
1330 GtkTreeModel *model = GTK_TREE_MODEL(city_model);
1332 gtk_tree_selection_unselect_all(city_selection);
1334 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
1335 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
1337 if (NULL != pcity
1338 && ((which == PCT_UNIT && VUT_UTYPE == pcity->production.kind)
1339 || (which == PCT_NORMAL_IMPROVEMENT
1340 && VUT_IMPROVEMENT == pcity->production.kind
1341 && !is_wonder(pcity->production.value.building))
1342 || (which == PCT_WONDER
1343 && VUT_IMPROVEMENT == pcity->production.kind
1344 && is_wonder(pcity->production.value.building)))) {
1345 itree_select(city_selection, &it);
1350 /****************************************************************************
1351 Buy the production in one single city.
1352 ****************************************************************************/
1353 static void buy_iterate(GtkTreeModel *model, GtkTreePath *path,
1354 GtkTreeIter *iter, gpointer data)
1356 struct city *pcity = city_model_get(model, iter);
1358 if (NULL != pcity) {
1359 cityrep_buy(pcity);
1363 /****************************************************************************
1364 Center to one single city.
1365 ****************************************************************************/
1366 static void center_iterate(GtkTreeModel *model, GtkTreePath *path,
1367 GtkTreeIter *iter, gpointer data)
1369 struct city *pcity = city_model_get(model, iter);
1371 if (NULL != pcity) {
1372 center_tile_mapcanvas(pcity->tile);
1376 /****************************************************************************
1377 Popup the dialog of a single city.
1378 ****************************************************************************/
1379 static void popup_iterate(GtkTreeModel *model, GtkTreePath *path,
1380 GtkTreeIter *iter, gpointer data)
1382 struct city *pcity = city_model_get(model, iter);
1384 if (NULL != pcity) {
1385 if (gui_options.center_when_popup_city) {
1386 center_tile_mapcanvas(pcity->tile);
1388 popup_city_dialog(pcity);
1392 /****************************************************************************
1393 gui_dialog response callback.
1394 ****************************************************************************/
1395 static void city_command_callback(struct gui_dialog *dlg, int response,
1396 gpointer data)
1398 switch (response) {
1399 case CITY_CENTER:
1400 if (1 == gtk_tree_selection_count_selected_rows(city_selection)) {
1401 /* Center to city doesn't make sense if many city are selected. */
1402 gtk_tree_selection_selected_foreach(city_selection, center_iterate,
1403 NULL);
1405 break;
1406 case CITY_POPUP:
1407 gtk_tree_selection_selected_foreach(city_selection, popup_iterate, NULL);
1408 break;
1409 case CITY_BUY:
1410 gtk_tree_selection_selected_foreach(city_selection, buy_iterate, NULL);
1411 break;
1412 default:
1413 gui_dialog_destroy(dlg);
1414 break;
1418 /****************************************************************
1419 User has selected city row from city report.
1420 *****************************************************************/
1421 static void city_activated_callback(GtkTreeView *view, GtkTreePath *path,
1422 GtkTreeViewColumn *col, gpointer data)
1424 GtkTreeModel *model;
1425 GtkTreeIter iter;
1426 GdkWindow *win;
1427 GdkDeviceManager *manager;
1428 GdkModifierType mask;
1430 model = gtk_tree_view_get_model(view);
1432 if (!gtk_tree_model_get_iter(model, &iter, path)) {
1433 return;
1436 win = gdk_get_default_root_window();
1437 manager = gdk_display_get_device_manager(gdk_window_get_display(win));
1439 gdk_window_get_device_position(win,
1440 gdk_device_manager_get_client_pointer(manager),
1441 NULL, NULL, &mask);
1443 if (!(mask & GDK_CONTROL_MASK)) {
1444 popup_iterate(model, path, &iter, NULL);
1445 } else {
1446 center_iterate(model, path, &iter, NULL);
1450 /****************************************************************************
1451 Update the city report dialog
1452 ****************************************************************************/
1453 void real_city_report_dialog_update(void)
1455 GHashTable *selected;
1456 ITree iter;
1457 gint city_id;
1459 if (NULL == city_dialog_shell) {
1460 return;
1463 /* Save the selection. */
1464 selected = g_hash_table_new(NULL, NULL);
1465 for (itree_begin(GTK_TREE_MODEL(city_model), &iter);
1466 !itree_end(&iter); itree_next(&iter)) {
1467 if (itree_is_selected(city_selection, &iter)) {
1468 itree_get(&iter, CRD_COL_CITY_ID, &city_id, -1);
1469 g_hash_table_insert(selected, GINT_TO_POINTER(city_id), NULL);
1473 /* Update and restore the selection. */
1474 gtk_list_store_clear(city_model);
1475 city_model_fill(city_model, city_selection, selected);
1476 g_hash_table_destroy(selected);
1478 if (gtk_widget_get_sensitive(city_governor_command)) {
1479 append_cma_to_menu_item(GTK_MENU_ITEM(city_governor_command), TRUE);
1482 select_menu_cached = FALSE;
1485 /****************************************************************************
1486 Update the text for a single city in the city report
1487 ****************************************************************************/
1488 void real_city_report_update_city(struct city *pcity)
1490 GtkTreeIter iter;
1492 if (NULL == city_dialog_shell) {
1493 return;
1496 if (!city_model_find(GTK_TREE_MODEL(city_model), &iter, pcity)) {
1497 gtk_list_store_prepend(city_model, &iter);
1499 city_model_set(city_model, &iter, pcity);
1501 update_total_buy_cost();
1504 /****************************************************************
1505 Create submenu for changing production target
1506 *****************************************************************/
1507 static void create_change_menu(GtkWidget *item)
1509 GtkWidget *menu;
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_change_menu), NULL);
1515 change_units_item = gtk_menu_item_new_with_label(_("Units"));
1516 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_units_item);
1517 change_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1518 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_improvements_item);
1519 change_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1520 gtk_menu_shell_append(GTK_MENU_SHELL(menu), change_wonders_item);
1523 /****************************************************************
1524 Creates the last menu.
1525 *****************************************************************/
1526 static void create_last_menu(GtkWidget *item)
1528 GtkWidget *menu;
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_last_menu), NULL);
1534 last_units_item = gtk_menu_item_new_with_label(_("Units"));
1535 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_units_item);
1536 last_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1537 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_improvements_item);
1538 last_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1539 gtk_menu_shell_append(GTK_MENU_SHELL(menu), last_wonders_item);
1542 /****************************************************************
1543 Creates the first menu.
1544 *****************************************************************/
1545 static void create_first_menu(GtkWidget *item)
1547 GtkWidget *menu;
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_first_menu), NULL);
1553 first_units_item = gtk_menu_item_new_with_label(_("Units"));
1554 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_units_item);
1555 first_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1556 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_improvements_item);
1557 first_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1558 gtk_menu_shell_append(GTK_MENU_SHELL(menu), first_wonders_item);
1561 /****************************************************************
1562 Creates the next menu.
1563 *****************************************************************/
1564 static void create_next_menu(GtkWidget *item)
1566 GtkWidget *menu;
1568 menu = gtk_menu_new();
1569 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1570 g_signal_connect(menu, "show", G_CALLBACK(popup_next_menu), NULL);
1572 next_units_item = gtk_menu_item_new_with_label(_("Units"));
1573 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_units_item);
1574 next_improvements_item = gtk_menu_item_new_with_label(_("Improvements"));
1575 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_improvements_item);
1576 next_wonders_item = gtk_menu_item_new_with_label(_("Wonders"));
1577 gtk_menu_shell_append(GTK_MENU_SHELL(menu), next_wonders_item);
1580 /**************************************************************************
1581 Append the "next to last" submenu to the given menu item.
1582 **************************************************************************/
1583 static void create_next_to_last_menu(GtkWidget *parent_item)
1585 GtkWidget *menu, *item;
1587 menu = gtk_menu_new();
1588 gtk_menu_item_set_submenu(GTK_MENU_ITEM(parent_item), menu);
1589 g_signal_connect(menu, "show",
1590 G_CALLBACK(popup_next_to_last_menu), NULL);
1592 item = gtk_menu_item_new_with_label(_("Units"));
1593 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1594 next_to_last_units_item = item;
1596 item = gtk_menu_item_new_with_label(_("Improvements"));
1597 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1598 next_to_last_improvements_item = item;
1600 item = gtk_menu_item_new_with_label(_("Wonders"));
1601 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1602 next_to_last_wonders_item = item;
1605 /****************************************************************
1606 Create the sell menu (empty).
1607 *****************************************************************/
1608 static void create_sell_menu(GtkWidget *item)
1610 GtkWidget *menu;
1612 menu = gtk_menu_new();
1613 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1617 /****************************************************************
1618 Pops up menu where user can select build target.
1619 *****************************************************************/
1620 static void popup_change_menu(GtkMenuShell *menu, gpointer data)
1622 int n;
1624 n = gtk_tree_selection_count_selected_rows(city_selection);
1626 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_improvements_item),
1627 FALSE, FALSE, CO_CHANGE,
1628 can_city_build_now,
1629 G_CALLBACK(select_impr_or_unit_callback), n);
1630 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(change_units_item),
1631 TRUE, FALSE, CO_CHANGE,
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(change_wonders_item),
1635 FALSE, TRUE, CO_CHANGE,
1636 can_city_build_now,
1637 G_CALLBACK(select_impr_or_unit_callback), n);
1640 /****************************************************************
1641 Pops up the last menu.
1642 *****************************************************************/
1643 static void popup_last_menu(GtkMenuShell *menu, gpointer data)
1645 int n;
1647 n = gtk_tree_selection_count_selected_rows(city_selection);
1649 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_improvements_item),
1650 FALSE, FALSE, CO_LAST,
1651 can_city_build_now,
1652 G_CALLBACK(select_impr_or_unit_callback), n);
1653 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(last_units_item),
1654 TRUE, FALSE, CO_LAST,
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(last_wonders_item),
1658 FALSE, TRUE, CO_LAST,
1659 can_city_build_now,
1660 G_CALLBACK(select_impr_or_unit_callback), n);
1663 /****************************************************************
1664 pops up the first menu.
1665 *****************************************************************/
1666 static void popup_first_menu(GtkMenuShell *menu, gpointer data)
1668 int n;
1670 n = gtk_tree_selection_count_selected_rows(city_selection);
1672 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_improvements_item),
1673 FALSE, FALSE, CO_FIRST,
1674 can_city_build_now,
1675 G_CALLBACK(select_impr_or_unit_callback), n);
1676 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(first_units_item),
1677 TRUE, FALSE, CO_FIRST,
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(first_wonders_item),
1681 FALSE, TRUE, CO_FIRST,
1682 can_city_build_now,
1683 G_CALLBACK(select_impr_or_unit_callback), n);
1686 /****************************************************************
1687 Pops up the next menu.
1688 *****************************************************************/
1689 static void popup_next_menu(GtkMenuShell *menu, gpointer data)
1691 int n;
1693 n = gtk_tree_selection_count_selected_rows(city_selection);
1695 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_improvements_item),
1696 FALSE, FALSE, CO_NEXT,
1697 can_city_build_now,
1698 G_CALLBACK(select_impr_or_unit_callback), n);
1699 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_units_item),
1700 TRUE, FALSE, CO_NEXT,
1701 can_city_build_now,
1702 G_CALLBACK(select_impr_or_unit_callback), n);
1703 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(next_wonders_item),
1704 FALSE, TRUE, CO_NEXT,
1705 can_city_build_now,
1706 G_CALLBACK(select_impr_or_unit_callback), n);
1709 /**************************************************************************
1710 Re-create the submenus in the next-to-last production change menu.
1711 **************************************************************************/
1712 static void popup_next_to_last_menu(GtkMenuShell *menu, gpointer data)
1714 GtkWidget *item;
1715 GCallback callback;
1716 int n;
1718 fc_assert_ret(city_selection != NULL);
1720 n = gtk_tree_selection_count_selected_rows(city_selection);
1721 callback = G_CALLBACK(select_impr_or_unit_callback);
1723 item = next_to_last_improvements_item;
1724 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1725 FALSE, FALSE, CO_NEXT_TO_LAST,
1726 can_city_build_now,
1727 callback, n);
1728 item = next_to_last_units_item;
1729 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1730 TRUE, FALSE, CO_NEXT_TO_LAST,
1731 can_city_build_now,
1732 callback, n);
1733 item = next_to_last_wonders_item;
1734 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(item),
1735 FALSE, TRUE, CO_NEXT_TO_LAST,
1736 can_city_build_now,
1737 callback, n);
1740 /****************************************************************
1741 Same as can_city_sell_building(), but with universal argument.
1742 *****************************************************************/
1743 static bool can_city_sell_universal(const struct city *pcity,
1744 const struct universal *target)
1746 return target->kind == VUT_IMPROVEMENT
1747 && can_city_sell_building(pcity, target->value.building);
1750 /****************************************************************
1751 Update the sell menu.
1752 *****************************************************************/
1753 static void recreate_sell_menu(void)
1755 int n;
1756 GList *children;
1757 GtkWidget *menu;
1759 n = gtk_tree_selection_count_selected_rows(city_selection);
1760 menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command));
1761 gtk_menu_popdown(GTK_MENU(menu));
1763 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(city_sell_command),
1764 FALSE, FALSE, CO_SELL,
1765 can_city_sell_universal,
1766 G_CALLBACK(select_impr_or_unit_callback),
1769 menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(city_sell_command));
1770 children = gtk_container_get_children(GTK_CONTAINER(menu));
1772 n = g_list_length(children);
1773 gtk_widget_set_sensitive(city_sell_command, n > 0);
1774 g_list_free(children);
1777 /****************************************************************
1778 Creates select menu
1779 *****************************************************************/
1780 static void create_select_menu(GtkWidget *item)
1782 GtkWidget *menu;
1784 menu = gtk_menu_new();
1785 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1786 g_signal_connect(menu, "show", G_CALLBACK(popup_select_menu), NULL);
1788 item = gtk_menu_item_new_with_label(_("All Cities"));
1789 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1790 g_signal_connect(item, "activate",
1791 G_CALLBACK(city_select_all_callback), NULL);
1793 item = gtk_menu_item_new_with_label(_("No Cities"));
1794 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1795 g_signal_connect(item, "activate",
1796 G_CALLBACK(city_unselect_all_callback), NULL);
1798 item = gtk_menu_item_new_with_label(_("Invert Selection"));
1799 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1800 g_signal_connect(item, "activate",
1801 G_CALLBACK(city_invert_selection_callback), NULL);
1804 item = gtk_separator_menu_item_new();
1805 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1808 item = gtk_menu_item_new_with_label(_("Building Units"));
1809 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1810 g_signal_connect(item, "activate",
1811 G_CALLBACK(city_select_building_callback),
1812 GINT_TO_POINTER(PCT_UNIT));
1814 item = gtk_menu_item_new_with_label( _("Building Improvements"));
1815 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1816 g_signal_connect(item, "activate",
1817 G_CALLBACK(city_select_building_callback),
1818 GINT_TO_POINTER(PCT_NORMAL_IMPROVEMENT));
1820 item = gtk_menu_item_new_with_label(_("Building Wonders"));
1821 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1822 g_signal_connect(item, "activate",
1823 G_CALLBACK(city_select_building_callback),
1824 GINT_TO_POINTER(PCT_WONDER));
1827 item = gtk_separator_menu_item_new();
1828 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1831 select_bunit_item =
1832 gtk_menu_item_new_with_label(_("Building Unit"));
1833 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bunit_item);
1835 select_bimprovement_item =
1836 gtk_menu_item_new_with_label( _("Building Improvement"));
1837 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bimprovement_item);
1839 select_bwonder_item =
1840 gtk_menu_item_new_with_label(_("Building Wonder"));
1841 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_bwonder_item);
1844 item = gtk_separator_menu_item_new();
1845 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1848 item = gtk_menu_item_new_with_label(_("Coastal Cities"));
1849 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1850 g_signal_connect(item, "activate",
1851 G_CALLBACK(city_select_coastal_callback), NULL);
1853 select_island_item = gtk_menu_item_new_with_label(_("Same Island"));
1854 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_island_item);
1855 g_signal_connect(select_island_item, "activate",
1856 G_CALLBACK(city_select_same_island_callback), NULL);
1859 item = gtk_separator_menu_item_new();
1860 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1863 select_supported_item = gtk_menu_item_new_with_label(_("Supported Units"));
1864 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_supported_item);
1866 select_present_item = gtk_menu_item_new_with_label(_("Units Present"));
1867 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_present_item);
1869 select_built_improvements_item =
1870 gtk_menu_item_new_with_label(_("Improvements in City"));
1871 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_built_improvements_item);
1873 select_built_wonders_item =
1874 gtk_menu_item_new_with_label(_("Wonders in City"));
1875 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_built_wonders_item);
1878 item = gtk_separator_menu_item_new();
1879 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1882 select_units_item =
1883 gtk_menu_item_new_with_label(_("Available Units"));
1884 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_units_item);
1885 select_improvements_item =
1886 gtk_menu_item_new_with_label(_("Available Improvements"));
1887 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_improvements_item);
1888 select_wonders_item =
1889 gtk_menu_item_new_with_label(_("Available Wonders"));
1890 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_wonders_item);
1891 select_cma_item =
1892 gtk_menu_item_new_with_label(_("Citizen Governor"));
1893 gtk_menu_shell_append(GTK_MENU_SHELL(menu), select_cma_item);
1896 /****************************************************************
1897 Returns whether city is building given target
1898 *****************************************************************/
1899 static bool city_building_impr_or_unit(const struct city *pcity,
1900 const struct universal *target)
1902 return are_universals_equal(&pcity->production, target);
1905 /****************************************************************
1906 Popup select menu
1907 *****************************************************************/
1908 static void popup_select_menu(GtkMenuShell *menu, gpointer data)
1910 int n;
1912 if (select_menu_cached)
1913 return;
1915 n = gtk_tree_selection_count_selected_rows(city_selection);
1916 gtk_widget_set_sensitive(select_island_item, (n > 0));
1918 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bunit_item),
1919 TRUE, FALSE, CO_NONE,
1920 city_building_impr_or_unit,
1921 G_CALLBACK(select_impr_or_unit_callback), -1);
1922 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bimprovement_item),
1923 FALSE, FALSE, CO_NONE,
1924 city_building_impr_or_unit,
1925 G_CALLBACK(select_impr_or_unit_callback), -1);
1926 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_bwonder_item),
1927 FALSE, TRUE, CO_NONE,
1928 city_building_impr_or_unit,
1929 G_CALLBACK(select_impr_or_unit_callback), -1);
1931 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_supported_item),
1932 TRUE, FALSE, CO_NONE,
1933 city_unit_supported,
1934 G_CALLBACK(select_impr_or_unit_callback), -1);
1935 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_present_item),
1936 TRUE, FALSE, CO_NONE,
1937 city_unit_present,
1938 G_CALLBACK(select_impr_or_unit_callback), -1);
1939 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_improvements_item),
1940 FALSE, FALSE, CO_NONE,
1941 city_building_present,
1942 G_CALLBACK(select_impr_or_unit_callback), -1);
1943 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_built_wonders_item),
1944 FALSE, TRUE, CO_NONE,
1945 city_building_present,
1946 G_CALLBACK(select_impr_or_unit_callback), -1);
1948 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_improvements_item),
1949 FALSE, FALSE, CO_NONE,
1950 can_city_build_now,
1951 G_CALLBACK(select_impr_or_unit_callback), -1);
1952 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_units_item),
1953 TRUE, FALSE, CO_NONE,
1954 can_city_build_now,
1955 G_CALLBACK(select_impr_or_unit_callback), -1);
1956 append_impr_or_unit_to_menu_item(GTK_MENU_ITEM(select_wonders_item),
1957 FALSE, TRUE, CO_NONE,
1958 can_city_build_now,
1959 G_CALLBACK(select_impr_or_unit_callback), -1);
1960 append_cma_to_menu_item(GTK_MENU_ITEM(select_cma_item), FALSE);
1962 select_menu_cached = TRUE;
1965 /***************************************************************************
1966 Update the value displayed by the "total buy cost" label in the city
1967 report, or make it blank if nothing can be bought.
1968 ***************************************************************************/
1969 static void update_total_buy_cost(void)
1971 GtkWidget *label, *view;
1972 GList *rows, *p;
1973 GtkTreeModel *model;
1974 GtkTreeSelection *sel;
1975 GtkTreePath *path;
1976 GtkTreeIter iter;
1977 struct city *pcity;
1978 int total = 0;
1980 view = city_view;
1981 label = city_total_buy_cost_label;
1983 if (!view || !label) {
1984 return;
1987 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
1988 rows = gtk_tree_selection_get_selected_rows(sel, &model);
1990 for (p = rows; p != NULL; p = p->next) {
1991 path = p->data;
1992 if (gtk_tree_model_get_iter(model, &iter, path)) {
1993 if ((pcity = city_model_get(model, &iter))) {
1994 total += city_production_buy_gold_cost(pcity);
1997 gtk_tree_path_free(path);
1999 g_list_free(rows);
2001 if (total > 0) {
2002 gchar *buf = g_strdup_printf(_("Total Buy Cost: %d"), total);
2003 gtk_label_set_text(GTK_LABEL(label), buf);
2004 g_free(buf);
2005 } else {
2006 gtk_label_set_text(GTK_LABEL(label), NULL);
2010 /***************************************************************************
2011 Update city report button sensitivity and total buy cost label when the
2012 user makes a change in the selection of cities.
2013 ***************************************************************************/
2014 static void city_selection_changed_callback(GtkTreeSelection *selection)
2016 int n;
2017 bool obs_may, plr_may;
2019 n = gtk_tree_selection_count_selected_rows(selection);
2020 obs_may = n > 0;
2021 plr_may = obs_may && can_client_issue_orders();
2023 gtk_widget_set_sensitive(city_production_command, plr_may);
2024 gtk_widget_set_sensitive(city_governor_command, plr_may);
2025 gtk_widget_set_sensitive(city_center_command, obs_may);
2026 gtk_widget_set_sensitive(city_popup_command, obs_may);
2027 gtk_widget_set_sensitive(city_buy_command, plr_may);
2028 if (plr_may) {
2029 recreate_sell_menu();
2030 } else {
2031 gtk_widget_set_sensitive(city_sell_command, FALSE);
2034 update_total_buy_cost();
2037 /**************************************************************************
2038 Clear the worklist in one selected city in the city report.
2039 **************************************************************************/
2040 static void clear_worklist_foreach_func(GtkTreeModel *model,
2041 GtkTreePath *path,
2042 GtkTreeIter *iter,
2043 gpointer data)
2045 struct city *pcity = city_model_get(model, iter);
2047 if (NULL != pcity) {
2048 struct worklist empty;
2050 worklist_init(&empty);
2051 city_set_worklist(pcity, &empty);
2055 /**************************************************************************
2056 Called when the "clear worklist" menu item is activated.
2057 **************************************************************************/
2058 static void city_clear_worklist_callback(GtkMenuItem *item, gpointer data)
2060 struct connection *pconn = &client.conn;
2062 fc_assert_ret(city_selection != NULL);
2064 connection_do_buffer(pconn);
2065 gtk_tree_selection_selected_foreach(city_selection,
2066 clear_worklist_foreach_func, NULL);
2067 connection_do_unbuffer(pconn);
2070 /****************************************************************
2071 After a selection rectangle is defined, make the cities that
2072 are hilited on the canvas exclusively hilited in the
2073 City List window.
2074 *****************************************************************/
2075 void hilite_cities_from_canvas(void)
2077 ITree it;
2078 GtkTreeModel *model;
2080 if (!city_dialog_shell) return;
2082 model = GTK_TREE_MODEL(city_model);
2084 gtk_tree_selection_unselect_all(city_selection);
2086 for (itree_begin(model, &it); !itree_end(&it); itree_next(&it)) {
2087 struct city *pcity = city_model_get(model, TREE_ITER_PTR(it));
2089 if (NULL != pcity && is_city_hilited(pcity)) {
2090 itree_select(city_selection, &it);
2095 /****************************************************************
2096 Toggle a city's hilited status.
2097 *****************************************************************/
2098 void toggle_city_hilite(struct city *pcity, bool on_off)
2100 GtkTreeIter iter;
2102 if (NULL == city_dialog_shell) {
2103 return;
2106 if (city_model_find(GTK_TREE_MODEL(city_model), &iter, pcity)) {
2107 if (on_off) {
2108 gtk_tree_selection_select_iter(city_selection, &iter);
2109 } else {
2110 gtk_tree_selection_unselect_iter(city_selection, &iter);