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, &parameter);
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(&parameter) == -1) {
718             select = TRUE;
719           }
720         } else if (cm_are_parameter_equal(&parameter,
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, &parameter) &&
801 	  cmafec_preset_get_index_of_parameter(&parameter) == -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, &parameter) &&
821 	    cm_are_parameter_equal(&parameter,
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