<URL: http://bugs.freeciv.org/Ticket/Display.html?id=40718 >

Patch implements a gui option to have new message events
appear at the top of the message window list, rather than
being added to the bottom (where they might be missed by
the user).

Since the old code assumed that the order of the messages
in the list store would always match the order of the
messages as they are in messagewin_common.c, the rest of
the patch is just to clean up all of the places in
messagewin.c where this poses a problem.


-----------------------------------------------------------------------
順序は重要だと花に言った。
 client/gui-gtk-2.0/gui_main.c   |    7 ++
 client/gui-gtk-2.0/gui_main.h   |    1 +
 client/gui-gtk-2.0/messagewin.c |  156 +++++++++++++++++++++-----------------
 3 files changed, 94 insertions(+), 70 deletions(-)

diff --git a/client/gui-gtk-2.0/gui_main.c b/client/gui-gtk-2.0/gui_main.c
index c3c0a70..109a055 100644
--- a/client/gui-gtk-2.0/gui_main.c
+++ b/client/gui-gtk-2.0/gui_main.c
@@ -95,6 +95,7 @@ int overview_canvas_store_height = 2 * 50;
 bool enable_tabs = TRUE;
 bool better_fog = TRUE;
 bool show_chat_message_time = FALSE;
+bool new_messages_go_to_top = FALSE;
 
 GtkWidget *toplevel;
 GdkWindow *root_window;
@@ -186,6 +187,12 @@ client_option gui_options[] = {
                   N_("If this option is enabled then all chat messages "
                      "will be prefixed by a time string of the form "
                      "[hour:minute:second]."),
+                  COC_NETWORK),
+  GEN_BOOL_OPTION(new_messages_go_to_top,
+                  N_("New message events go to top of list"),
+                  N_("If this option is enabled, new events in the "
+                     "message window will appear at the top of the list, "
+                     "rather than being appended at the bottom."),
                   COC_INTERFACE)
 };
 const int num_gui_options = ARRAY_SIZE(gui_options);
diff --git a/client/gui-gtk-2.0/gui_main.h b/client/gui-gtk-2.0/gui_main.h
index 9f9205e..28e521e 100644
--- a/client/gui-gtk-2.0/gui_main.h
+++ b/client/gui-gtk-2.0/gui_main.h
@@ -27,6 +27,7 @@ extern PangoFontDescription *        city_productions_font;
 extern bool enable_tabs;
 extern bool better_fog;
 extern bool show_chat_message_time;
+extern bool new_messages_go_to_top;
 
 extern GdkGC *          civ_gc;
 extern GdkGC *          mask_fg_gc;
diff --git a/client/gui-gtk-2.0/messagewin.c b/client/gui-gtk-2.0/messagewin.c
index 1844e27..d099e81 100644
--- a/client/gui-gtk-2.0/messagewin.c
+++ b/client/gui-gtk-2.0/messagewin.c
@@ -98,27 +98,17 @@ bool is_meswin_open(void)
 /****************************************************************
 ...
 *****************************************************************/
-static void meswin_visited_item(gint n)
+static void meswin_set_visited(GtkTreeIter *it, bool visited)
 {
-  GtkTreeIter it;
-
-  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(meswin_store),&it,NULL,n)) {
-    gtk_list_store_set(meswin_store, &it, 1, (gint)TRUE, -1);
-    set_message_visited_state(n, TRUE);
-  }
-}
+  GtkListStore *store;
+  gint row;
 
-/****************************************************************
-...
-*****************************************************************/
-static void meswin_not_visited_item(gint n)
-{
-  GtkTreeIter it;
+  store = meswin_store;
+  g_return_if_fail(store != NULL);
 
-  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(meswin_store),&it,NULL,n)) {
-    gtk_list_store_set(meswin_store, &it, 1, (gint)FALSE, -1);
-    set_message_visited_state(n, FALSE);
-  }
+  gtk_list_store_set(store, it, 1, visited, -1);
+  gtk_tree_model_get(GTK_TREE_MODEL(store), it, 2, &row, -1);
+  set_message_visited_state(row, visited);
 }
 
 /****************************************************************
@@ -152,8 +142,12 @@ static gboolean meswin_button_press_callback(GtkWidget *widget,
                                              gpointer data)
 {
   GtkTreePath *path = NULL;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
   gint row;
 
+  g_return_val_if_fail(GTK_IS_TREE_VIEW(widget), FALSE);
+
   if (ev->type != GDK_BUTTON_PRESS || ev->button != 3) {
     return FALSE;
   }
@@ -164,11 +158,13 @@ static gboolean meswin_button_press_callback(GtkWidget *widget,
     return TRUE;
   }
 
-  row = gtk_tree_path_get_indices(path)[0];
+  model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+  if (gtk_tree_model_get_iter(model, &iter, path)) {
+    gtk_tree_model_get(model, &iter, 2, &row, -1);
+    meswin_goto(row);
+  }
   gtk_tree_path_free(path);
 
-  meswin_goto(row);
-
   return TRUE;
 }
 
@@ -184,7 +180,9 @@ static void create_meswin_dialog(void)
   gui_dialog_new(&meswin_shell, GTK_NOTEBOOK(bottom_notebook), NULL);
   gui_dialog_set_title(meswin_shell, _("Messages"));
 
-  meswin_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+  meswin_store = gtk_list_store_new(3, G_TYPE_STRING,
+                                    G_TYPE_BOOLEAN,
+                                    G_TYPE_INT);
 
   sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
@@ -237,25 +235,29 @@ static void create_meswin_dialog(void)
 **************************************************************************/
 void real_update_meswin_dialog(void)
 {
-  int i, num = get_num_messages(), num_not_visited = 0;
+  int i, num, num_not_visited = 0;
+  struct message *pmsg;
+  GtkListStore *store;
   GtkTreeIter it;
 
-  gtk_list_store_clear(meswin_store);
+  store = meswin_store;
+  g_return_if_fail(store != NULL);
 
-  for (i = 0; i < num; i++) {
-    GValue value = { 0, };
-
-    gtk_list_store_append(meswin_store, &it);
+  gtk_list_store_clear(store);
+  num = get_num_messages();
 
-    g_value_init(&value, G_TYPE_STRING);
-    g_value_set_static_string(&value, get_message(i)->descr);
-    gtk_list_store_set_value(meswin_store, &it, 0, &value);
-    g_value_unset(&value);
+  for (i = 0; i < num; i++) {
+    pmsg = get_message(i);
 
-    if (get_message(i)->visited) {
-      meswin_visited_item(i);
+    if (new_messages_go_to_top) {
+      gtk_list_store_prepend(store, &it);
     } else {
-      meswin_not_visited_item(i);
+      gtk_list_store_append(store, &it);
+    }
+    gtk_list_store_set(store, &it, 0, pmsg->descr, 2, i, -1);
+    meswin_set_visited(&it, pmsg->visited);
+
+    if (!pmsg->visited) {
       num_not_visited++;
     }
   }
@@ -274,15 +276,23 @@ void real_update_meswin_dialog(void)
 static void meswin_selection_callback(GtkTreeSelection *selection,
 				      gpointer data)
 {
-  gint row = gtk_tree_selection_get_row(selection);
+  struct message *pmsg;
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  gint row;
 
-  if (row != -1) {
-    struct message *message = get_message(row);
+  if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
+    return;
+  }
 
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+  pmsg = get_message(row);
+
+  if (pmsg) {
     gui_dialog_set_response_sensitive(meswin_shell, CMD_GOTO,
-	message->location_ok);
+                                      pmsg->location_ok);
     gui_dialog_set_response_sensitive(meswin_shell, CMD_POPCITY,
-	message->city_ok);
+                                      pmsg->city_ok);
   }
 }
 
@@ -294,16 +304,26 @@ static void meswin_row_activated_callback(GtkTreeView *view,
 					  GtkTreeViewColumn *col,
 					  gpointer data)
 {
-  gint row = gtk_tree_path_get_indices(path)[0];
-  struct message *message = get_message(row);
+  struct message *pmsg;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint row;
+
+  model = gtk_tree_view_get_model(view);
+  if (!gtk_tree_model_get_iter(model, &iter, path)) {
+    return;
+  }
+
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+  pmsg = get_message(row);
 
   meswin_double_click(row);
-  meswin_visited_item(row);
+  meswin_set_visited(&iter, TRUE);
 
   gui_dialog_set_response_sensitive(meswin_shell, CMD_GOTO,
-      message->location_ok);
+                                    pmsg->location_ok);
   gui_dialog_set_response_sensitive(meswin_shell, CMD_POPCITY,
-      message->city_ok);
+                                    pmsg->city_ok);
 }
 
 /**************************************************************************
@@ -312,33 +332,29 @@ static void meswin_row_activated_callback(GtkTreeView *view,
 static void meswin_response_callback(struct gui_dialog *dlg, int response,
                                      gpointer data)
 {
-  switch (response) {
-  case CMD_GOTO:
-    {
-      gint row = gtk_tree_selection_get_row(meswin_selection);
-
-      if (row == -1) {
-	return;
-      }
+  GtkTreeSelection *sel;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint row;
 
-      meswin_goto(row);
-      meswin_visited_item(row);
-    }
-    break;
-  case CMD_POPCITY:
-    {
-      gint row = gtk_tree_selection_get_row(meswin_selection);
-
-      if (row == -1) {
-	return;
-      }
-      meswin_popup_city(row);
-      meswin_visited_item(row);
-    }
-    break;
-  default:
+  if (response != CMD_GOTO && response != CMD_POPCITY) {
     gui_dialog_destroy(dlg);
-    break;
+    return;
+  }
+
+  sel = meswin_selection;
+  g_return_if_fail(sel != NULL);
+  if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
+    return;
+  }
+
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+
+  if (response == CMD_GOTO) {
+    meswin_goto(row);
+  } else {
+    meswin_popup_city(row);
   }
+  meswin_set_visited(&iter, TRUE);
 }
 
 client/gui-gtk-2.0/gui_main.c   |    7 ++
 client/gui-gtk-2.0/gui_main.h   |    1 +
 client/gui-gtk-2.0/messagewin.c |  156 +++++++++++++++++++++-----------------
 3 files changed, 94 insertions(+), 70 deletions(-)

diff --git a/client/gui-gtk-2.0/gui_main.c b/client/gui-gtk-2.0/gui_main.c
index 12e66c0..3ff846b 100644
--- a/client/gui-gtk-2.0/gui_main.c
+++ b/client/gui-gtk-2.0/gui_main.c
@@ -98,6 +98,7 @@ int overview_canvas_store_height = 2 * 50;
 bool enable_tabs = TRUE;
 bool better_fog = TRUE;
 bool show_chat_message_time = FALSE;
+bool new_messages_go_to_top = FALSE;
 
 GtkWidget *toplevel;
 GdkWindow *root_window;
@@ -206,6 +207,12 @@ client_option gui_options[] = {
                      "will be prefixed by a time string of the form "
                      "[hour:minute:second]."),
                   COC_INTERFACE),
+  GEN_BOOL_OPTION(new_messages_go_to_top,
+                  N_("New message events go to top of list"),
+                  N_("If this option is enabled, new events in the "
+                     "message window will appear at the top of the list, "
+                     "rather than being appended at the bottom."),
+                  COC_INTERFACE),
   GEN_FONT_OPTION(font_city_label,
   		  city_label,
 		  N_("City Label"),
diff --git a/client/gui-gtk-2.0/gui_main.h b/client/gui-gtk-2.0/gui_main.h
index 98e5a7a..6c21bd9 100644
--- a/client/gui-gtk-2.0/gui_main.h
+++ b/client/gui-gtk-2.0/gui_main.h
@@ -27,6 +27,7 @@ extern PangoFontDescription *        city_productions_font;
 extern bool enable_tabs;
 extern bool better_fog;
 extern bool show_chat_message_time;
+extern bool new_messages_go_to_top;
 
 extern GdkGC *          civ_gc;
 extern GdkGC *          mask_fg_gc;
diff --git a/client/gui-gtk-2.0/messagewin.c b/client/gui-gtk-2.0/messagewin.c
index 0bfa55a..4b796eb 100644
--- a/client/gui-gtk-2.0/messagewin.c
+++ b/client/gui-gtk-2.0/messagewin.c
@@ -97,27 +97,17 @@ bool is_meswin_open(void)
 /****************************************************************
 ...
 *****************************************************************/
-static void meswin_visited_item(gint n)
+static void meswin_set_visited(GtkTreeIter *it, bool visited)
 {
-  GtkTreeIter it;
-
-  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(meswin_store),&it,NULL,n)) {
-    gtk_list_store_set(meswin_store, &it, 1, (gint)TRUE, -1);
-    set_message_visited_state(n, TRUE);
-  }
-}
+  GtkListStore *store;
+  gint row;
 
-/****************************************************************
-...
-*****************************************************************/
-static void meswin_not_visited_item(gint n)
-{
-  GtkTreeIter it;
+  store = meswin_store;
+  g_return_if_fail(store != NULL);
 
-  if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(meswin_store),&it,NULL,n)) {
-    gtk_list_store_set(meswin_store, &it, 1, (gint)FALSE, -1);
-    set_message_visited_state(n, FALSE);
-  }
+  gtk_list_store_set(store, it, 1, visited, -1);
+  gtk_tree_model_get(GTK_TREE_MODEL(store), it, 2, &row, -1);
+  set_message_visited_state(row, visited);
 }
 
 /****************************************************************
@@ -151,8 +141,12 @@ static gboolean meswin_button_press_callback(GtkWidget *widget,
                                              gpointer data)
 {
   GtkTreePath *path = NULL;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
   gint row;
 
+  g_return_val_if_fail(GTK_IS_TREE_VIEW(widget), FALSE);
+
   if (ev->type != GDK_BUTTON_PRESS || ev->button != 3) {
     return FALSE;
   }
@@ -163,11 +157,13 @@ static gboolean meswin_button_press_callback(GtkWidget *widget,
     return TRUE;
   }
 
-  row = gtk_tree_path_get_indices(path)[0];
+  model = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
+  if (gtk_tree_model_get_iter(model, &iter, path)) {
+    gtk_tree_model_get(model, &iter, 2, &row, -1);
+    meswin_goto(row);
+  }
   gtk_tree_path_free(path);
 
-  meswin_goto(row);
-
   return TRUE;
 }
 
@@ -183,7 +179,9 @@ static void create_meswin_dialog(void)
   gui_dialog_new(&meswin_shell, GTK_NOTEBOOK(bottom_notebook), NULL);
   gui_dialog_set_title(meswin_shell, _("Messages"));
 
-  meswin_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+  meswin_store = gtk_list_store_new(3, G_TYPE_STRING,
+                                    G_TYPE_BOOLEAN,
+                                    G_TYPE_INT);
 
   sw = gtk_scrolled_window_new(NULL, NULL);
   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
@@ -236,25 +234,29 @@ static void create_meswin_dialog(void)
 **************************************************************************/
 void real_update_meswin_dialog(void)
 {
-  int i, num = get_num_messages(), num_not_visited = 0;
+  int i, num, num_not_visited = 0;
+  struct message *pmsg;
+  GtkListStore *store;
   GtkTreeIter it;
 
-  gtk_list_store_clear(meswin_store);
+  store = meswin_store;
+  g_return_if_fail(store != NULL);
 
-  for (i = 0; i < num; i++) {
-    GValue value = { 0, };
-
-    gtk_list_store_append(meswin_store, &it);
+  gtk_list_store_clear(store);
+  num = get_num_messages();
 
-    g_value_init(&value, G_TYPE_STRING);
-    g_value_set_static_string(&value, get_message(i)->descr);
-    gtk_list_store_set_value(meswin_store, &it, 0, &value);
-    g_value_unset(&value);
+  for (i = 0; i < num; i++) {
+    pmsg = get_message(i);
 
-    if (get_message(i)->visited) {
-      meswin_visited_item(i);
+    if (new_messages_go_to_top) {
+      gtk_list_store_prepend(store, &it);
     } else {
-      meswin_not_visited_item(i);
+      gtk_list_store_append(store, &it);
+    }
+    gtk_list_store_set(store, &it, 0, pmsg->descr, 2, i, -1);
+    meswin_set_visited(&it, pmsg->visited);
+
+    if (!pmsg->visited) {
       num_not_visited++;
     }
   }
@@ -273,15 +275,23 @@ void real_update_meswin_dialog(void)
 static void meswin_selection_callback(GtkTreeSelection *selection,
 				      gpointer data)
 {
-  gint row = gtk_tree_selection_get_row(selection);
+  struct message *pmsg;
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  gint row;
 
-  if (row != -1) {
-    struct message *message = get_message(row);
+  if (!gtk_tree_selection_get_selected(selection, &model, &iter)) {
+    return;
+  }
 
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+  pmsg = get_message(row);
+
+  if (pmsg) {
     gui_dialog_set_response_sensitive(meswin_shell, CMD_GOTO,
-	message->location_ok);
+                                      pmsg->location_ok);
     gui_dialog_set_response_sensitive(meswin_shell, CMD_POPCITY,
-	message->city_ok);
+                                      pmsg->city_ok);
   }
 }
 
@@ -293,16 +303,26 @@ static void meswin_row_activated_callback(GtkTreeView *view,
 					  GtkTreeViewColumn *col,
 					  gpointer data)
 {
-  gint row = gtk_tree_path_get_indices(path)[0];
-  struct message *message = get_message(row);
+  struct message *pmsg;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint row;
+
+  model = gtk_tree_view_get_model(view);
+  if (!gtk_tree_model_get_iter(model, &iter, path)) {
+    return;
+  }
+
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+  pmsg = get_message(row);
 
   meswin_double_click(row);
-  meswin_visited_item(row);
+  meswin_set_visited(&iter, TRUE);
 
   gui_dialog_set_response_sensitive(meswin_shell, CMD_GOTO,
-      message->location_ok);
+                                    pmsg->location_ok);
   gui_dialog_set_response_sensitive(meswin_shell, CMD_POPCITY,
-      message->city_ok);
+                                    pmsg->city_ok);
 }
 
 /**************************************************************************
@@ -311,33 +331,29 @@ static void meswin_row_activated_callback(GtkTreeView *view,
 static void meswin_response_callback(struct gui_dialog *dlg, int response,
                                      gpointer data)
 {
-  switch (response) {
-  case CMD_GOTO:
-    {
-      gint row = gtk_tree_selection_get_row(meswin_selection);
-
-      if (row == -1) {
-	return;
-      }
+  GtkTreeSelection *sel;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint row;
 
-      meswin_goto(row);
-      meswin_visited_item(row);
-    }
-    break;
-  case CMD_POPCITY:
-    {
-      gint row = gtk_tree_selection_get_row(meswin_selection);
-
-      if (row == -1) {
-	return;
-      }
-      meswin_popup_city(row);
-      meswin_visited_item(row);
-    }
-    break;
-  default:
+  if (response != CMD_GOTO && response != CMD_POPCITY) {
     gui_dialog_destroy(dlg);
-    break;
+    return;
+  }
+
+  sel = meswin_selection;
+  g_return_if_fail(sel != NULL);
+  if (!gtk_tree_selection_get_selected(sel, &model, &iter)) {
+    return;
+  }
+
+  gtk_tree_model_get(model, &iter, 2, &row, -1);
+
+  if (response == CMD_GOTO) {
+    meswin_goto(row);
+  } else {
+    meswin_popup_city(row);
   }
+  meswin_set_visited(&iter, TRUE);
 }
 
_______________________________________________
Freeciv-dev mailing list
Freeciv-dev@gna.org
https://mail.gna.org/listinfo/freeciv-dev

Reply via email to