Qt client - remove right click menu from end turn sidebar
[freeciv.git] / client / gui-gtk-3.0 / wldlg.c
blob1637092bd35cbb649635b92320914319e0c84aa8
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 <stdlib.h>
19 #include <string.h>
21 #include <gtk/gtk.h>
22 #include <gdk/gdkkeysyms.h>
24 /* utility */
25 #include "fcintl.h"
26 #include "log.h"
27 #include "mem.h"
28 #include "support.h"
30 /* common */
31 #include "city.h"
32 #include "packets.h"
33 #include "worklist.h"
35 /* client */
36 #include "citydlg_common.h"
37 #include "client_main.h"
38 #include "climisc.h"
39 #include "global_worklist.h"
40 #include "options.h"
41 #include "tilespec.h"
43 /* client/gui-gtk-3.0 */
44 #include "canvas.h"
45 #include "citydlg.h"
46 #include "graphics.h"
47 #include "gui_main.h"
48 #include "gui_stuff.h"
49 #include "helpdlg.h"
50 #include "inputdlg.h"
52 #include "wldlg.h"
54 static GtkWidget *worklists_shell;
55 static GtkWidget *worklists_list;
57 enum {
58 WORKLISTS_NEW,
59 WORKLISTS_DELETE,
60 WORKLISTS_PROPERTIES,
61 WORKLISTS_CLOSE
64 static GtkListStore *worklists_store;
66 static int max_unit_height = -1, max_unit_width = -1;
68 static void reset_global_worklist(GtkWidget *editor,
69 struct global_worklist *pgwl);
70 static void popup_worklist(struct global_worklist *pgwl);
71 static void popdown_worklist(struct global_worklist *pgwl);
72 static void dst_row_callback(GtkTreeView *view, GtkTreePath *path,
73 GtkTreeViewColumn *col, gpointer data);
75 /****************************************************************
76 Illegal initialization value for max unit size variables
77 *****************************************************************/
78 void blank_max_unit_size(void)
80 max_unit_height = -1;
81 max_unit_width = -1;
84 /****************************************************************
85 Setup max unit sprite size.
86 *****************************************************************/
87 static void update_max_unit_size(void)
89 max_unit_height = 0;
90 max_unit_width = 0;
92 unit_type_iterate(i) {
93 int x1, x2, y1, y2;
94 struct sprite *sprite = get_unittype_sprite(tileset, i,
95 direction8_invalid(), TRUE);
97 sprite_get_bounding_box(sprite, &x1, &y1, &x2, &y2);
98 max_unit_width = MAX(max_unit_width, x2 - x1);
99 max_unit_height = MAX(max_unit_height, y2 - y1);
100 } unit_type_iterate_end;
104 /****************************************************************
105 Worklists dialog being destroyed
106 *****************************************************************/
107 static void worklists_destroy_callback(GtkWidget *w, gpointer data)
109 worklists_shell = NULL;
113 /****************************************************************
114 Refresh global worklists list
115 *****************************************************************/
116 void update_worklist_report_dialog(void)
118 GtkTreeIter it;
120 gtk_list_store_clear(worklists_store);
121 global_worklists_iterate(pgwl) {
122 gtk_list_store_append(worklists_store, &it);
124 gtk_list_store_set(worklists_store, &it,
125 0, global_worklist_name(pgwl),
126 1, global_worklist_id(pgwl),
127 -1);
128 } global_worklists_iterate_end;
131 /****************************************************************
132 User has responded to worklist report
133 *****************************************************************/
134 static void worklists_response(GtkWidget *w, gint response)
136 struct global_worklist *pgwl;
137 int id;
138 GtkTreeSelection *selection;
139 GtkTreeModel *model;
140 GtkTreeIter it;
142 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(worklists_list));
144 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
145 gtk_tree_model_get(model, &it, 1, &id, -1);
146 pgwl = global_worklist_by_id(id);
147 } else {
148 pgwl = NULL;
149 id = -1;
152 switch (response) {
153 case WORKLISTS_NEW:
154 global_worklist_new(_("new"));
155 update_worklist_report_dialog();
156 return;
158 case WORKLISTS_DELETE:
159 if (!pgwl) {
160 return;
163 popdown_worklist(pgwl);
164 global_worklist_destroy(pgwl);
165 update_worklist_report_dialog();
166 return;
168 case WORKLISTS_PROPERTIES:
169 if (!pgwl) {
170 return;
173 popup_worklist(pgwl);
174 return;
176 default:
177 gtk_widget_destroy(worklists_shell);
178 return;
182 /****************************************************************
183 Worklist cell edited
184 *****************************************************************/
185 static void cell_edited(GtkCellRendererText *cell,
186 const gchar *spath,
187 const gchar *text, gpointer data)
189 GtkTreePath *path;
190 GtkTreeIter it;
191 struct global_worklist *pgwl;
192 int id;
194 path = gtk_tree_path_new_from_string(spath);
195 gtk_tree_model_get_iter(GTK_TREE_MODEL(worklists_store), &it, path);
196 gtk_tree_path_free(path);
198 gtk_tree_model_get(GTK_TREE_MODEL(worklists_store), &it, 1, &id, -1);
199 pgwl = global_worklist_by_id(id);
201 if (!pgwl) {
202 gtk_list_store_remove(worklists_store, &it);
203 return;
206 global_worklist_set_name(pgwl, text);
207 gtk_list_store_set(worklists_store, &it, 0, text, -1);
210 /****************************************************************
211 Bring up the global worklist report.
212 *****************************************************************/
213 static GtkWidget *create_worklists_report(void)
215 GtkWidget *shell, *list;
216 GtkWidget *vbox, *label, *sw;
217 GtkCellRenderer *rend;
219 shell = gtk_dialog_new_with_buttons(_("Edit worklists"),
220 NULL,
222 GTK_STOCK_NEW,
223 WORKLISTS_NEW,
224 GTK_STOCK_DELETE,
225 WORKLISTS_DELETE,
226 GTK_STOCK_PROPERTIES,
227 WORKLISTS_PROPERTIES,
228 GTK_STOCK_CLOSE,
229 WORKLISTS_CLOSE,
230 NULL);
231 setup_dialog(shell, toplevel);
232 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
234 g_signal_connect(shell, "response",
235 G_CALLBACK(worklists_response), NULL);
236 g_signal_connect(shell, "destroy",
237 G_CALLBACK(worklists_destroy_callback), NULL);
239 vbox = gtk_grid_new();
240 gtk_grid_set_row_spacing(GTK_GRID(vbox), 2);
241 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
242 GTK_ORIENTATION_VERTICAL);
243 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), vbox);
245 worklists_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
247 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(worklists_store));
248 gtk_widget_set_hexpand(list, TRUE);
249 gtk_widget_set_vexpand(list, TRUE);
251 g_object_unref(worklists_store);
252 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
254 worklists_list = list;
256 rend = gtk_cell_renderer_text_new();
257 g_object_set(rend, "editable", TRUE, NULL);
258 g_signal_connect(rend, "edited",
259 G_CALLBACK(cell_edited), NULL);
260 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(list), -1, NULL,
261 rend, "text", 0, NULL);
263 sw = gtk_scrolled_window_new(NULL, NULL);
264 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
265 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
266 GTK_SHADOW_ETCHED_IN);
267 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
268 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
269 gtk_container_add(GTK_CONTAINER(sw), list);
271 label = g_object_new(GTK_TYPE_LABEL,
272 "use-underline", TRUE,
273 "mnemonic-widget", list,
274 "label", _("_Worklists:"),
275 "xalign", 0.0, "yalign", 0.5, NULL);
277 gtk_container_add(GTK_CONTAINER(vbox), label);
278 gtk_container_add(GTK_CONTAINER(vbox), sw);
279 gtk_widget_show_all(vbox);
281 return shell;
284 /****************************************************************
285 Open worklists report
286 *****************************************************************/
287 void popup_worklists_report(void)
289 if (!worklists_shell) {
290 worklists_shell = create_worklists_report();
292 update_worklist_report_dialog();
295 gtk_window_present(GTK_WINDOW(worklists_shell));
301 /****************************************************************
303 *****************************************************************/
304 struct worklist_data {
305 int global_worklist_id;
306 struct city *pcity;
308 GtkWidget *editor;
310 GtkListStore *src, *dst;
311 GtkWidget *src_view, *dst_view;
312 GtkTreeSelection *src_selection, *dst_selection;
314 GtkTreeViewColumn *src_col, *dst_col;
316 GtkWidget *add_cmd, *change_cmd, *help_cmd;
317 GtkWidget *up_cmd, *down_cmd, *prepend_cmd, *append_cmd, *remove_cmd;
319 bool future;
322 static GHashTable *hash;
324 static void commit_worklist(struct worklist_data *ptr);
327 enum {
328 TARGET_GTK_TREE_MODEL_ROW
331 static GtkTargetEntry wl_dnd_targets[] = {
332 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_GTK_TREE_MODEL_ROW },
337 /****************************************************************
338 Add drag&drop target
339 *****************************************************************/
340 void add_worklist_dnd_target(GtkWidget *w)
342 gtk_drag_dest_set(w, GTK_DEST_DEFAULT_ALL,
343 wl_dnd_targets, G_N_ELEMENTS(wl_dnd_targets),
344 GDK_ACTION_COPY);
347 /****************************************************************
348 Get worklist by id
349 *****************************************************************/
350 static GtkWidget *get_worklist(int global_worklist_id)
352 if (hash) {
353 gpointer ret;
355 ret = g_hash_table_lookup(hash, GINT_TO_POINTER(global_worklist_id));
356 return ret;
357 } else {
358 return NULL;
362 /****************************************************************
363 Insert worklist to editor
364 *****************************************************************/
365 static void insert_worklist(int global_worklist_id, GtkWidget *editor)
367 if (!hash) {
368 hash = g_hash_table_new(g_direct_hash, g_direct_equal);
370 g_hash_table_insert(hash, GINT_TO_POINTER(global_worklist_id), editor);
373 /****************************************************************
374 Remove worklist from hash
375 *****************************************************************/
376 static void delete_worklist(int global_worklist_id)
378 if (hash) {
379 g_hash_table_remove(hash, GINT_TO_POINTER(global_worklist_id));
383 /****************************************************************
384 User responded to worklist report
385 *****************************************************************/
386 static void worklist_response(GtkWidget *shell, gint response)
388 gtk_widget_destroy(shell);
391 /****************************************************************
392 Worklist editor window used by the global worklist report.
393 *****************************************************************/
394 static void popup_worklist(struct global_worklist *pgwl)
396 GtkWidget *shell;
398 if (!(shell = get_worklist(global_worklist_id(pgwl)))) {
399 GtkWidget *editor;
401 shell = gtk_dialog_new_with_buttons(global_worklist_name(pgwl),
402 GTK_WINDOW(worklists_shell),
403 GTK_DIALOG_DESTROY_WITH_PARENT,
404 GTK_STOCK_CLOSE,
405 GTK_RESPONSE_CLOSE,
406 NULL);
407 gtk_window_set_role(GTK_WINDOW(shell), "worklist");
408 gtk_window_set_position(GTK_WINDOW(shell), GTK_WIN_POS_MOUSE);
409 g_signal_connect(shell, "response", G_CALLBACK(worklist_response), NULL);
410 gtk_window_set_default_size(GTK_WINDOW(shell), 500, 400);
412 editor = create_worklist();
413 reset_global_worklist(editor, pgwl);
414 insert_worklist(global_worklist_id(pgwl), editor);
416 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(shell))), editor);
417 gtk_widget_show(editor);
419 refresh_worklist(editor);
422 gtk_window_present(GTK_WINDOW(shell));
425 /****************************************************************
426 Close worklist
427 *****************************************************************/
428 static void popdown_worklist(struct global_worklist *pgwl)
430 GtkWidget *shell;
432 if ((shell = get_worklist(global_worklist_id(pgwl)))) {
433 GtkWidget *parent;
435 parent = gtk_widget_get_toplevel(shell);
436 gtk_widget_destroy(parent);
440 /****************************************************************
441 Destroy worklist
442 *****************************************************************/
443 static void worklist_destroy(GtkWidget *editor, gpointer data)
445 struct worklist_data *ptr;
447 ptr = data;
449 if (ptr->global_worklist_id != -1) {
450 delete_worklist(ptr->global_worklist_id);
453 free(ptr);
456 /****************************************************************
457 Item activated from menu
458 *****************************************************************/
459 static void menu_item_callback(GtkMenuItem *item, struct worklist_data *ptr)
461 struct global_worklist *pgwl;
462 const struct worklist *pwl;
463 size_t i;
465 if (NULL == client.conn.playing) {
466 return;
469 pgwl = global_worklist_by_id(GPOINTER_TO_INT
470 (g_object_get_data(G_OBJECT(item), "id")));
471 if (!pgwl) {
472 return;
474 pwl = global_worklist_get(pgwl);
476 for (i = 0; i < (size_t) worklist_length(pwl); i++) {
477 GtkTreeIter it;
478 cid id;
480 id = cid_encode(pwl->entries[i]);
482 gtk_list_store_append(ptr->dst, &it);
483 gtk_list_store_set(ptr->dst, &it, 0, (gint) id, -1);
486 commit_worklist(ptr);
489 /****************************************************************
490 Open menu for adding items to worklist
491 *****************************************************************/
492 static void popup_add_menu(GtkMenuShell *menu, gpointer data)
494 GtkWidget *item;
496 gtk_container_foreach(GTK_CONTAINER(menu),
497 (GtkCallback) gtk_widget_destroy, NULL);
499 global_worklists_iterate(pgwl) {
500 item = gtk_menu_item_new_with_label(global_worklist_name(pgwl));
501 g_object_set_data(G_OBJECT(item), "id",
502 GINT_TO_POINTER(global_worklist_id(pgwl)));
503 gtk_widget_show(item);
505 gtk_container_add(GTK_CONTAINER(menu), item);
506 g_signal_connect(item, "activate",
507 G_CALLBACK(menu_item_callback), data);
508 } global_worklists_iterate_end;
510 item = gtk_separator_menu_item_new();
511 gtk_widget_show(item);
513 gtk_container_add(GTK_CONTAINER(menu), item);
515 item = gtk_menu_item_new_with_mnemonic(_("Edit Global _Worklists"));
516 gtk_widget_show(item);
518 gtk_container_add(GTK_CONTAINER(menu), item);
519 g_signal_connect(item, "activate",
520 G_CALLBACK(popup_worklists_report), NULL);
523 /****************************************************************
524 Help button clicked
525 *****************************************************************/
526 static void help_callback(GtkWidget *w, gpointer data)
528 struct worklist_data *ptr;
529 GtkTreeSelection *selection;
530 GtkTreeModel *model;
531 GtkTreeIter it;
533 ptr = data;
534 selection = ptr->src_selection;
536 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
537 gint id;
538 struct universal target;
540 gtk_tree_model_get(model, &it, 0, &id, -1);
541 target = cid_decode(id);
543 if (VUT_UTYPE == target.kind) {
544 popup_help_dialog_typed(utype_name_translation(target.value.utype),
545 HELP_UNIT);
546 } else if (is_great_wonder(target.value.building)) {
547 popup_help_dialog_typed(improvement_name_translation(target.value.building),
548 HELP_WONDER);
549 } else {
550 popup_help_dialog_typed(improvement_name_translation(target.value.building),
551 HELP_IMPROVEMENT);
553 } else {
554 popup_help_dialog_string(HELP_WORKLIST_EDITOR_ITEM);
558 /****************************************************************
559 "Change Production" clicked
560 *****************************************************************/
561 static void change_callback(GtkWidget *w, gpointer data)
563 struct worklist_data *ptr;
564 GtkTreeSelection *selection;
565 GtkTreeModel *model;
566 GtkTreeIter it;
568 ptr = data;
569 selection = ptr->src_selection;
571 if (gtk_tree_selection_get_selected(selection, &model, &it)) {
572 gint id;
573 struct universal univ;
575 gtk_tree_model_get(model, &it, 0, &id, -1);
576 univ = cid_production(id);
577 city_change_production(ptr->pcity, &univ);
581 /****************************************************************
582 Showing of future targets toggled
583 *****************************************************************/
584 static void future_callback(GtkToggleButton *toggle, gpointer data)
586 struct worklist_data *ptr;
588 ptr = data;
589 ptr->future = !ptr->future;
591 refresh_worklist(ptr->editor);
594 /****************************************************************
595 Move item up in worklist
596 *****************************************************************/
597 static void queue_bubble_up(struct worklist_data *ptr)
599 GtkTreePath *path;
600 GtkTreeViewColumn *col;
601 GtkTreeModel *model;
603 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
604 return;
607 model = GTK_TREE_MODEL(ptr->dst);
608 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
609 if (path) {
610 GtkTreeIter it, it_prev;
612 if (gtk_tree_path_prev(path)) {
613 gtk_tree_model_get_iter(model, &it_prev, path);
614 it = it_prev;
615 gtk_tree_model_iter_next(model, &it);
617 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_prev);
619 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
620 commit_worklist(ptr);
623 gtk_tree_path_free(path);
626 /****************************************************************
627 Removal of the item requested
628 *****************************************************************/
629 static void queue_remove(struct worklist_data *ptr)
631 GtkTreePath *path;
632 GtkTreeViewColumn *col;
634 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
635 if (path) {
636 dst_row_callback(GTK_TREE_VIEW(ptr->dst_view), path, col, ptr);
637 gtk_tree_path_free(path);
641 /****************************************************************
642 Move item down in queue
643 *****************************************************************/
644 static void queue_bubble_down(struct worklist_data *ptr)
646 GtkTreePath *path;
647 GtkTreeViewColumn *col;
648 GtkTreeModel *model;
650 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
651 return;
654 model = GTK_TREE_MODEL(ptr->dst);
655 gtk_tree_view_get_cursor(GTK_TREE_VIEW(ptr->dst_view), &path, &col);
656 if (path) {
657 GtkTreeIter it, it_next;
659 gtk_tree_model_get_iter(model, &it, path);
660 it_next = it;
661 if (gtk_tree_model_iter_next(model, &it_next)) {
662 gtk_list_store_swap(GTK_LIST_STORE(model), &it, &it_next);
664 gtk_tree_path_next(path);
665 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->dst_view), path, col, FALSE);
666 commit_worklist(ptr);
669 gtk_tree_path_free(path);
672 /****************************************************************
673 Insert item to queue
674 *****************************************************************/
675 static void queue_insert(struct worklist_data *ptr, bool prepend)
677 GtkTreeModel *model;
678 GtkTreeIter it;
679 GtkTreePath *path;
681 GtkTreeModel *src_model, *dst_model;
682 GtkTreeIter src_it, dst_it;
683 gint i, ncols;
685 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
686 return;
689 if (!gtk_tree_selection_get_selected(ptr->src_selection, &model, &it)) {
690 return;
693 path = gtk_tree_model_get_path(model, &it);
695 src_model = GTK_TREE_MODEL(ptr->src);
696 dst_model = GTK_TREE_MODEL(ptr->dst);
698 gtk_tree_model_get_iter(src_model, &src_it, path);
699 if (prepend) {
700 gtk_list_store_prepend(GTK_LIST_STORE(dst_model), &dst_it);
701 } else {
702 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
705 ncols = gtk_tree_model_get_n_columns(src_model);
707 for (i = 0; i < ncols; i++) {
708 GValue value = { 0, };
710 gtk_tree_model_get_value(src_model, &src_it, i, &value);
711 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
713 commit_worklist(ptr);
715 gtk_tree_path_free(path);
718 /****************************************************************
719 Prepend item to worklist
720 *****************************************************************/
721 static void queue_prepend(struct worklist_data *ptr)
723 queue_insert(ptr, TRUE);
726 /****************************************************************
727 Append item to worklist
728 *****************************************************************/
729 static void queue_append(struct worklist_data *ptr)
731 queue_insert(ptr, FALSE);
734 /****************************************************************
735 Source row activated
736 *****************************************************************/
737 static void src_row_callback(GtkTreeView *view, GtkTreePath *path,
738 GtkTreeViewColumn *col, gpointer data)
740 struct worklist_data *ptr;
741 GtkTreeModel *src_model, *dst_model;
742 GtkTreeIter src_it, dst_it;
743 gint i, ncols;
745 ptr = data;
747 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
748 return;
751 src_model = GTK_TREE_MODEL(ptr->src);
752 dst_model = GTK_TREE_MODEL(ptr->dst);
754 gtk_tree_model_get_iter(src_model, &src_it, path);
755 gtk_list_store_append(GTK_LIST_STORE(dst_model), &dst_it);
757 ncols = gtk_tree_model_get_n_columns(src_model);
759 for (i = 0; i < ncols; i++) {
760 GValue value = { 0, };
762 gtk_tree_model_get_value(src_model, &src_it, i, &value);
763 gtk_list_store_set_value(GTK_LIST_STORE(dst_model), &dst_it, i, &value);
765 commit_worklist(ptr);
768 /****************************************************************
769 Destination row activated
770 *****************************************************************/
771 static void dst_row_callback(GtkTreeView *view, GtkTreePath *path,
772 GtkTreeViewColumn *col, gpointer data)
774 struct worklist_data *ptr;
775 GtkTreeModel *dst_model;
776 GtkTreeIter it;
778 ptr = data;
779 dst_model = GTK_TREE_MODEL(ptr->dst);
781 gtk_tree_model_get_iter(dst_model, &it, path);
783 gtk_list_store_remove(GTK_LIST_STORE(dst_model), &it);
784 commit_worklist(ptr);
787 /****************************************************************
788 Key press for source
789 *****************************************************************/
790 static gboolean src_key_press_callback(GtkWidget *w, GdkEventKey *ev,
791 gpointer data)
793 struct worklist_data *ptr;
795 ptr = data;
797 if (!gtk_widget_is_sensitive(ptr->dst_view)) {
798 return FALSE;
801 if ((ev->state & GDK_SHIFT_MASK) && ev->keyval == GDK_KEY_Insert) {
802 queue_prepend(ptr);
803 return TRUE;
804 } else if (ev->keyval == GDK_KEY_Insert) {
805 queue_append(ptr);
806 return TRUE;
807 } else {
808 return FALSE;
812 /****************************************************************
813 Key press for destination
814 *****************************************************************/
815 static gboolean dst_key_press_callback(GtkWidget *w, GdkEventKey *ev,
816 gpointer data)
818 GtkTreeModel *model;
819 struct worklist_data *ptr;
821 ptr = data;
822 model = GTK_TREE_MODEL(ptr->dst);
824 if (ev->keyval == GDK_KEY_Delete) {
825 GtkTreeIter it, it_next;
826 bool deleted = FALSE;
828 if (gtk_tree_model_get_iter_first(model, &it)) {
829 bool more;
831 do {
832 it_next = it;
833 more = gtk_tree_model_iter_next(model, &it_next);
835 if (gtk_tree_selection_iter_is_selected(ptr->dst_selection, &it)) {
836 gtk_list_store_remove(GTK_LIST_STORE(model), &it);
837 deleted = TRUE;
839 it = it_next;
841 } while (more);
844 if (deleted) {
845 commit_worklist(ptr);
847 return TRUE;
849 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Up) {
850 queue_bubble_up(ptr);
851 return TRUE;
853 } else if ((ev->state & GDK_MOD1_MASK) && ev->keyval == GDK_KEY_Down) {
854 queue_bubble_down(ptr);
855 return TRUE;
857 } else {
858 return FALSE;
862 /****************************************************************
863 Selection from source
864 *****************************************************************/
865 static void src_selection_callback(GtkTreeSelection *selection, gpointer data)
867 struct worklist_data *ptr;
869 ptr = data;
871 /* update widget sensitivity. */
872 if (gtk_tree_selection_get_selected(selection, NULL, NULL)) {
873 if (can_client_issue_orders()
874 && (!ptr->pcity || city_owner(ptr->pcity) == client.conn.playing)) {
875 /* if ptr->pcity is NULL, this is a global worklist */
876 gtk_widget_set_sensitive(ptr->change_cmd, TRUE);
877 gtk_widget_set_sensitive(ptr->prepend_cmd, TRUE);
878 gtk_widget_set_sensitive(ptr->append_cmd, TRUE);
879 } else {
880 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
881 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
882 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
884 gtk_widget_set_sensitive(ptr->help_cmd, TRUE);
885 } else {
886 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
887 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
888 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
889 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
893 /****************************************************************
894 Selection from destination
895 *****************************************************************/
896 static void dst_selection_callback(GtkTreeSelection *selection, gpointer data)
898 struct worklist_data *ptr;
900 ptr = data;
902 /* update widget sensitivity. */
903 if (gtk_tree_selection_count_selected_rows(selection) > 0) {
904 int num_rows = 0;
905 GtkTreeIter it;
907 gtk_widget_set_sensitive(ptr->up_cmd, TRUE);
908 gtk_widget_set_sensitive(ptr->down_cmd, TRUE);
909 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ptr->dst), &it)) {
910 do {
911 num_rows++;
912 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(ptr->dst), &it));
914 if (num_rows > 1) {
915 gtk_widget_set_sensitive(ptr->remove_cmd, TRUE);
916 } else {
917 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
919 } else {
920 gtk_widget_set_sensitive(ptr->up_cmd, FALSE);
921 gtk_widget_set_sensitive(ptr->down_cmd, FALSE);
922 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
926 /****************************************************************
927 Drag&drop to destination
928 *****************************************************************/
929 static gboolean dst_dnd_callback(GtkWidget *w, GdkDragContext *context,
930 struct worklist_data *ptr)
932 commit_worklist(ptr);
933 return FALSE;
936 /****************************************************************
937 Render worklist cell
938 *****************************************************************/
939 static void cell_render_func(GtkTreeViewColumn *col, GtkCellRenderer *rend,
940 GtkTreeModel *model, GtkTreeIter *it,
941 gpointer data)
943 gint id;
944 struct universal target;
946 gtk_tree_model_get(model, it, 0, &id, -1);
947 target = cid_production(id);
949 if (GTK_IS_CELL_RENDERER_PIXBUF(rend)) {
950 GdkPixbuf *pix;
951 struct sprite *sprite;
953 if (VUT_UTYPE == target.kind) {
954 sprite = sprite_scale(get_unittype_sprite(tileset, target.value.utype,
955 direction8_invalid(), TRUE),
956 max_unit_width, max_unit_height);
958 } else {
959 sprite = get_building_sprite(tileset, target.value.building);
962 pix = sprite_get_pixbuf(sprite);
963 g_object_set(rend, "pixbuf", pix, NULL);
964 g_object_unref(G_OBJECT(pix));
965 if (VUT_UTYPE == target.kind) {
966 free_sprite(sprite);
968 } else {
969 struct city **pcity = data;
970 gint column;
971 char *row[4];
972 char buf[4][64];
973 guint i;
974 gboolean useless;
976 for (i = 0; i < ARRAY_SIZE(row); i++) {
977 row[i] = buf[i];
979 column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(rend), "column"));
981 get_city_dialog_production_row(row, sizeof(buf[0]), &target, *pcity);
982 g_object_set(rend, "text", row[column], NULL);
984 if (NULL != *pcity && VUT_IMPROVEMENT == target.kind) {
985 useless = is_improvement_redundant(*pcity, target.value.building);
986 /* Mark building redundant if we are really certain that there is
987 * no use for it. */
988 g_object_set(rend, "strikethrough", useless, NULL);
989 } else {
990 g_object_set(rend, "strikethrough", FALSE, NULL);
995 /****************************************************************
996 Populate view with buildable item information
997 *****************************************************************/
998 static void populate_view(GtkTreeView *view, struct city **ppcity,
999 GtkTreeViewColumn **pcol)
1001 static const char *titles[] =
1002 { N_("Type"), N_("Name"), N_("Info"), N_("Cost"), N_("Turns") };
1004 static bool titles_done;
1005 guint i;
1006 GtkCellRenderer *rend;
1007 GtkTreeViewColumn *col;
1009 intl_slist(ARRAY_SIZE(titles), titles, &titles_done);
1011 /* Case i == 0 taken out of the loop to workaround gcc-4.2.1 bug
1012 * http://gcc.gnu.org/PR33381
1013 * Some values would 'stick' from i == 0 round. */
1014 i = 0;
1016 rend = gtk_cell_renderer_pixbuf_new();
1018 gtk_tree_view_insert_column_with_data_func(view,
1019 i, titles[i], rend, cell_render_func, ppcity, NULL);
1020 col = gtk_tree_view_get_column(view, i);
1022 if (gui_options.gui_gtk3_show_task_icons) {
1023 if (max_unit_width == -1 || max_unit_height == -1) {
1024 update_max_unit_size();
1026 } else {
1027 g_object_set(col, "visible", FALSE, NULL);
1029 if (gui_options.gui_gtk3_show_task_icons) {
1030 g_object_set(rend, "height", max_unit_height, NULL);
1033 for (i = 1; i < ARRAY_SIZE(titles); i++) {
1035 gint pos = i-1;
1037 rend = gtk_cell_renderer_text_new();
1038 g_object_set_data(G_OBJECT(rend), "column", GINT_TO_POINTER(pos));
1040 gtk_tree_view_insert_column_with_data_func(view,
1041 i, titles[i], rend, cell_render_func, ppcity, NULL);
1042 col = gtk_tree_view_get_column(view, i);
1044 if (pos >= 2) {
1045 g_object_set(G_OBJECT(rend), "xalign", 1.0, NULL);
1046 gtk_tree_view_column_set_alignment(col, 1.0);
1049 if (pos == 3) {
1050 *pcol = col;
1052 if (gui_options.gui_gtk3_show_task_icons) {
1053 g_object_set(rend, "height", max_unit_height, NULL);
1058 /****************************************************************
1059 Worklist editor shell.
1060 *****************************************************************/
1061 GtkWidget *create_worklist(void)
1063 GtkWidget *editor, *table, *sw, *bbox;
1064 GtkWidget *src_view, *dst_view, *label, *button;
1065 GtkWidget *menubar, *item, *menu, *image;
1066 GtkWidget *table2, *arrow, *check;
1067 GtkSizeGroup *group;
1068 GtkListStore *src_store, *dst_store;
1069 struct worklist_data *ptr;
1071 ptr = fc_malloc(sizeof(*ptr));
1073 src_store = gtk_list_store_new(1, G_TYPE_INT);
1074 dst_store = gtk_list_store_new(1, G_TYPE_INT);
1076 ptr->global_worklist_id = -1;
1077 ptr->pcity = NULL;
1078 ptr->src = src_store;
1079 ptr->dst = dst_store;
1080 ptr->future = FALSE;
1082 /* create shell. */
1083 editor = gtk_grid_new();
1084 gtk_grid_set_row_spacing(GTK_GRID(editor), 6);
1085 gtk_orientable_set_orientation(GTK_ORIENTABLE(editor),
1086 GTK_ORIENTATION_VERTICAL);
1087 g_signal_connect(editor, "destroy", G_CALLBACK(worklist_destroy), ptr);
1088 g_object_set_data(G_OBJECT(editor), "data", ptr);
1090 ptr->editor = editor;
1092 /* add source and target lists. */
1093 table = gtk_grid_new();
1094 gtk_container_add(GTK_CONTAINER(editor), table);
1096 group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1098 sw = gtk_scrolled_window_new(NULL, NULL);
1099 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1100 GTK_SHADOW_ETCHED_IN);
1101 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1102 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1103 gtk_grid_attach(GTK_GRID(table), sw, 3, 1, 2, 1);
1105 src_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(src_store));
1106 gtk_widget_set_hexpand(src_view, TRUE);
1107 gtk_widget_set_vexpand(src_view, TRUE);
1108 g_object_unref(src_store);
1109 gtk_size_group_add_widget(group, src_view);
1110 gtk_widget_set_name(src_view, "small_font");
1112 populate_view(GTK_TREE_VIEW(src_view), &ptr->pcity, &ptr->src_col);
1113 gtk_container_add(GTK_CONTAINER(sw), src_view);
1115 label = g_object_new(GTK_TYPE_LABEL,
1116 "use-underline", TRUE,
1117 "mnemonic-widget", src_view,
1118 "label", _("Source _Tasks:"),
1119 "xalign", 0.0, "yalign", 0.5, NULL);
1120 gtk_grid_attach(GTK_GRID(table), label, 3, 0, 1, 1);
1122 check = gtk_check_button_new_with_mnemonic(_("Show _Future Targets"));
1123 gtk_grid_attach(GTK_GRID(table), check, 4, 0, 1, 1);
1124 g_signal_connect(check, "toggled", G_CALLBACK(future_callback), ptr);
1126 table2 = gtk_grid_new();
1127 gtk_grid_attach(GTK_GRID(table), table2, 2, 1, 1, 1);
1129 button = gtk_button_new();
1130 gtk_widget_set_margin_top(button, 24);
1131 gtk_widget_set_margin_bottom(button, 24);
1132 ptr->prepend_cmd = button;
1133 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1134 gtk_grid_attach(GTK_GRID(table2), button, 0, 0, 1, 1);
1136 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1137 gtk_container_add(GTK_CONTAINER(button), arrow);
1138 g_signal_connect_swapped(button, "clicked",
1139 G_CALLBACK(queue_prepend), ptr);
1140 gtk_widget_set_sensitive(ptr->prepend_cmd, FALSE);
1142 button = gtk_button_new();
1143 ptr->up_cmd = button;
1144 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1145 gtk_grid_attach(GTK_GRID(table2), button, 0, 1, 1, 1);
1147 arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE);
1148 gtk_container_add(GTK_CONTAINER(button), arrow);
1149 g_signal_connect_swapped(button, "clicked",
1150 G_CALLBACK(queue_bubble_up), ptr);
1151 gtk_widget_set_sensitive(ptr->up_cmd, FALSE);
1153 button = gtk_button_new();
1154 ptr->down_cmd = button;
1155 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1156 gtk_grid_attach(GTK_GRID(table2), button, 0, 2, 1, 1);
1158 arrow = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_IN);
1159 gtk_container_add(GTK_CONTAINER(button), arrow);
1160 g_signal_connect_swapped(button, "clicked",
1161 G_CALLBACK(queue_bubble_down), ptr);
1162 gtk_widget_set_sensitive(ptr->down_cmd, FALSE);
1164 button = gtk_button_new();
1165 gtk_widget_set_margin_top(button, 24);
1166 gtk_widget_set_margin_bottom(button, 24);
1167 ptr->append_cmd = button;
1168 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1169 gtk_grid_attach(GTK_GRID(table2), button, 0, 3, 1, 1);
1171 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
1172 gtk_container_add(GTK_CONTAINER(button), arrow);
1173 g_signal_connect_swapped(button, "clicked",
1174 G_CALLBACK(queue_append), ptr);
1175 gtk_widget_set_sensitive(ptr->append_cmd, FALSE);
1177 button = gtk_button_new();
1178 gtk_widget_set_margin_top(button, 24);
1179 gtk_widget_set_margin_bottom(button, 24);
1180 ptr->remove_cmd = button;
1181 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1182 gtk_grid_attach(GTK_GRID(table2), button, 0, 4, 1, 1);
1184 arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_IN);
1185 gtk_container_add(GTK_CONTAINER(button), arrow);
1186 g_signal_connect_swapped(button, "clicked",
1187 G_CALLBACK(queue_remove), ptr);
1188 gtk_widget_set_sensitive(ptr->remove_cmd, FALSE);
1190 sw = gtk_scrolled_window_new(NULL, NULL);
1191 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1192 GTK_SHADOW_ETCHED_IN);
1193 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1194 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1195 gtk_grid_attach(GTK_GRID(table), sw, 0, 1, 2, 1);
1197 dst_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dst_store));
1198 gtk_widget_set_hexpand(dst_view, TRUE);
1199 gtk_widget_set_vexpand(dst_view, TRUE);
1200 g_object_unref(dst_store);
1201 gtk_size_group_add_widget(group, dst_view);
1202 gtk_widget_set_name(dst_view, "small_font");
1204 populate_view(GTK_TREE_VIEW(dst_view), &ptr->pcity, &ptr->dst_col);
1205 gtk_container_add(GTK_CONTAINER(sw), dst_view);
1207 label = g_object_new(GTK_TYPE_LABEL,
1208 "use-underline", TRUE,
1209 "mnemonic-widget", dst_view,
1210 "label", _("Target _Worklist:"),
1211 "xalign", 0.0, "yalign", 0.5, NULL);
1212 gtk_grid_attach(GTK_GRID(table), label, 0, 0, 1, 1);
1214 /* add bottom menu and buttons. */
1215 bbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
1216 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
1217 gtk_box_set_spacing(GTK_BOX(bbox), 10);
1218 gtk_container_add(GTK_CONTAINER(editor), bbox);
1220 menubar = gtk_aux_menu_bar_new();
1221 gtk_container_add(GTK_CONTAINER(bbox), menubar);
1222 gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(bbox), menubar, TRUE);
1224 menu = gtk_menu_new();
1226 image = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
1227 item = gtk_image_menu_item_new_with_mnemonic(_("_Add Global Worklist"));
1228 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
1229 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), menu);
1230 gtk_menu_shell_append(GTK_MENU_SHELL(menubar), item);
1231 g_signal_connect(menu, "show",
1232 G_CALLBACK(popup_add_menu), ptr);
1233 ptr->add_cmd = item;
1234 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1236 button = gtk_button_new_from_stock(GTK_STOCK_HELP);
1237 gtk_container_add(GTK_CONTAINER(bbox), button);
1238 g_signal_connect(button, "clicked",
1239 G_CALLBACK(help_callback), ptr);
1240 ptr->help_cmd = button;
1241 gtk_widget_set_sensitive(ptr->help_cmd, FALSE);
1243 button = gtk_button_new_with_mnemonic(_("Change Prod_uction"));
1244 gtk_container_add(GTK_CONTAINER(bbox), button);
1245 g_signal_connect(button, "clicked",
1246 G_CALLBACK(change_callback), ptr);
1247 ptr->change_cmd = button;
1248 gtk_widget_set_sensitive(ptr->change_cmd, FALSE);
1250 ptr->src_view = src_view;
1251 ptr->dst_view = dst_view;
1252 ptr->src_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(src_view));
1253 ptr->dst_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dst_view));
1254 gtk_tree_selection_set_mode(ptr->dst_selection, GTK_SELECTION_MULTIPLE);
1256 /* DND and other state changing callbacks. */
1257 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(dst_view), TRUE);
1258 g_signal_connect(dst_view, "drag_end",
1259 G_CALLBACK(dst_dnd_callback), ptr);
1261 g_signal_connect(src_view, "row_activated",
1262 G_CALLBACK(src_row_callback), ptr);
1263 g_signal_connect(src_view, "key_press_event",
1264 G_CALLBACK(src_key_press_callback), ptr);
1266 g_signal_connect(dst_view, "row_activated",
1267 G_CALLBACK(dst_row_callback), ptr);
1268 g_signal_connect(dst_view, "key_press_event",
1269 G_CALLBACK(dst_key_press_callback), ptr);
1271 g_signal_connect(ptr->src_selection, "changed",
1272 G_CALLBACK(src_selection_callback), ptr);
1273 g_signal_connect(ptr->dst_selection, "changed",
1274 G_CALLBACK(dst_selection_callback), ptr);
1277 gtk_widget_show_all(table);
1278 gtk_widget_show_all(bbox);
1280 return editor;
1284 /****************************************************************
1285 Reset worklist for city
1286 *****************************************************************/
1287 void reset_city_worklist(GtkWidget *editor, struct city *pcity)
1289 struct worklist_data *ptr;
1291 ptr = g_object_get_data(G_OBJECT(editor), "data");
1293 ptr->global_worklist_id = -1;
1294 ptr->pcity = pcity;
1296 gtk_list_store_clear(ptr->src);
1297 gtk_list_store_clear(ptr->dst);
1299 g_object_set(ptr->src_col, "visible", TRUE, NULL);
1300 g_object_set(ptr->dst_col, "visible", TRUE, NULL);
1302 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(ptr->src_view),
1303 GDK_BUTTON1_MASK,
1304 wl_dnd_targets,
1305 G_N_ELEMENTS(wl_dnd_targets),
1306 GDK_ACTION_COPY);
1309 /****************************************************************
1310 Reset one of the global worklists
1311 *****************************************************************/
1312 static void reset_global_worklist(GtkWidget *editor,
1313 struct global_worklist *pgwl)
1315 struct worklist_data *ptr;
1317 ptr = g_object_get_data(G_OBJECT(editor), "data");
1319 ptr->global_worklist_id = global_worklist_id(pgwl);
1320 ptr->pcity = NULL;
1322 gtk_list_store_clear(ptr->src);
1323 gtk_list_store_clear(ptr->dst);
1325 gtk_widget_hide(ptr->change_cmd);
1326 g_object_set(ptr->src_col, "visible", FALSE, NULL);
1327 g_object_set(ptr->dst_col, "visible", FALSE, NULL);
1329 gtk_tree_view_unset_rows_drag_source(GTK_TREE_VIEW(ptr->src_view));
1332 /****************************************************************
1333 Refresh worklist info
1334 *****************************************************************/
1335 void refresh_worklist(GtkWidget *editor)
1337 struct worklist_data *ptr;
1338 struct worklist queue;
1339 struct universal targets[MAX_NUM_PRODUCTION_TARGETS];
1340 int i, targets_used;
1341 struct item items[MAX_NUM_PRODUCTION_TARGETS];
1342 bool selected;
1343 gint id;
1344 GtkTreeIter it;
1345 GtkTreePath *path;
1346 GtkTreeModel *model;
1347 gboolean exists;
1349 ptr = g_object_get_data(G_OBJECT(editor), "data");
1351 /* refresh source tasks. */
1352 if (gtk_tree_selection_get_selected(ptr->src_selection, NULL, &it)) {
1353 gtk_tree_model_get(GTK_TREE_MODEL(ptr->src), &it, 0, &id, -1);
1354 selected = TRUE;
1355 } else {
1356 selected = FALSE;
1358 gtk_list_store_clear(ptr->src);
1360 /* These behave just right if ptr->pcity is NULL -> in case of global
1361 * worklist. */
1362 targets_used = collect_eventually_buildable_targets(targets, ptr->pcity,
1363 ptr->future);
1364 name_and_sort_items(targets, targets_used, items, FALSE, ptr->pcity);
1366 path = NULL;
1367 for (i = 0; i < targets_used; i++) {
1368 gtk_list_store_append(ptr->src, &it);
1369 gtk_list_store_set(ptr->src, &it, 0, (gint) cid_encode(items[i].item), -1);
1371 if (selected && cid_encode(items[i].item) == id) {
1372 path = gtk_tree_model_get_path(GTK_TREE_MODEL(ptr->src), &it);
1375 if (path) {
1376 gtk_tree_view_set_cursor(GTK_TREE_VIEW(ptr->src_view), path, NULL, FALSE);
1377 gtk_tree_path_free(path);
1381 /* refresh target worklist. */
1382 model = GTK_TREE_MODEL(ptr->dst);
1383 exists = gtk_tree_model_get_iter_first(model, &it);
1385 /* dance around worklist braindamage. */
1386 if (ptr->pcity != NULL) {
1387 city_get_queue(ptr->pcity, &queue);
1388 } else {
1389 const struct global_worklist *pgwl;
1391 pgwl = global_worklist_by_id(ptr->global_worklist_id);
1393 fc_assert(NULL != pgwl);
1395 worklist_copy(&queue, global_worklist_get(pgwl));
1398 for (i = 0; i < worklist_length(&queue); i++) {
1399 struct universal target = queue.entries[i];
1401 if (!exists) {
1402 gtk_list_store_append(ptr->dst, &it);
1405 gtk_list_store_set(ptr->dst, &it, 0, (gint) cid_encode(target), -1);
1407 if (exists) {
1408 exists = gtk_tree_model_iter_next(model, &it);
1412 if (exists) {
1413 GtkTreeIter it_next;
1414 bool more;
1416 do {
1417 it_next = it;
1418 more = gtk_tree_model_iter_next(model, &it_next);
1420 gtk_list_store_remove(ptr->dst, &it);
1421 it = it_next;
1422 } while (more);
1425 /* update widget sensitivity. */
1426 if (ptr->pcity) {
1427 if ((can_client_issue_orders()
1428 && city_owner(ptr->pcity) == client.conn.playing)) {
1429 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1430 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1431 } else {
1432 gtk_widget_set_sensitive(ptr->add_cmd, FALSE);
1433 gtk_widget_set_sensitive(ptr->dst_view, FALSE);
1435 } else {
1436 gtk_widget_set_sensitive(ptr->add_cmd, TRUE);
1437 gtk_widget_set_sensitive(ptr->dst_view, TRUE);
1441 /****************************************************************
1442 Commit worklist data to worklist
1443 *****************************************************************/
1444 static void commit_worklist(struct worklist_data *ptr)
1446 struct worklist queue;
1447 GtkTreeModel *model;
1448 GtkTreeIter it;
1449 size_t i;
1451 model = GTK_TREE_MODEL(ptr->dst);
1453 worklist_init(&queue);
1455 i = 0;
1456 if (gtk_tree_model_get_iter_first(model, &it)) {
1457 do {
1458 gint id;
1459 struct universal univ;
1461 /* oops, the player has a worklist longer than what we can store. */
1462 if (i >= MAX_LEN_WORKLIST) {
1463 break;
1466 gtk_tree_model_get(model, &it, 0, &id, -1);
1467 univ = cid_production(id);
1468 worklist_append(&queue, &univ);
1470 i++;
1471 } while (gtk_tree_model_iter_next(model, &it));
1474 /* dance around worklist braindamage. */
1475 if (ptr->pcity) {
1476 if (!city_set_queue(ptr->pcity, &queue)) {
1477 /* Failed to change worklist. This means worklist visible
1478 * on screen is not true. */
1479 refresh_worklist(ptr->editor);
1481 } else {
1482 struct global_worklist *pgwl;
1484 pgwl = global_worklist_by_id(ptr->global_worklist_id);
1485 if (pgwl) {
1486 global_worklist_set(pgwl, &queue);