#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include "../gm-support.h" #include "../gm-debug.h" #include "../gm-app.h" #include "gm-worlds-list-dialog.h" #include "gm-world-properties-dialog.h" #include "../gm-pixbuf.h" typedef struct _GmWorldsListDialog { GladeXML *xml; GtkWidget *dialog; GtkTreeView *tree_view_worlds; GtkTreeModel *model_worlds; } GmWorldsListDialog; void on_gm_worlds_list_dialog_button_delete_clicked(GtkButton * utton, gpointer user_data); void on_gm_worlds_list_dialog_button_new_clicked(GtkButton *button, gpointer user_data); void on_gm_worlds_list_dialog_button_modify_clicked(GtkButton *button, gpointer user_data); void on_gm_worlds_list_dialog_button_duplicate_clicked(GtkButton *button, gpointer user_data); void on_gm_worlds_list_dialog_button_connect_clicked(GtkButton *button, gpointer user_data); void on_gm_worlds_list_dialog_tree_view_worlds_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data); void on_gm_worlds_list_dialog_app_world_added(GmApp *app, GmWorld *world, gpointer user_data); void on_gm_worlds_list_dialog_app_world_removed(GmApp *app, GmWorld *world, gpointer user_data); void on_gm_worlds_list_dialog_world_option_changed(GmOptions *options, const gchar *key, GmWorld *world); void on_gm_worlds_list_dialog_response(GtkDialog *dialog, gint response, gpointer user_data); static GmWorldsListDialog *gm_worlds_list_dialog_instance; enum { LOGO_COLUMN, NAME_COLUMN, WORLD_COLUMN, N_COLUMNS }; GtkWidget * gm_worlds_list_dialog_widget(gchar *name) { return glade_xml_get_widget(gm_worlds_list_dialog_instance->xml, name); } gchar * gm_worlds_list_dialog_world_text(GmWorld *world) { gchar *text; const gchar *player, *server; GmOptions *options = gm_world_options(world); player = gm_options_get(options, "player_name"); server = gm_options_get(options, "host"); text = g_strconcat("", gm_options_get(options, "name"), _("\nServer: "), ((server && server[0] != '\0') ? server : _("unspecified")), _("\nPlayer: "), ((player && player[0] != '\0') ? player : _("unspecified")), NULL); return text; } static void gm_worlds_list_dialog_add_world(GmWorld *world) { GtkTreeIter iter; GdkPixbuf *pix_logo = NULL; gchar *name = gm_worlds_list_dialog_world_text(world); const gchar *logo = gm_options_get(gm_world_options(world), "logo"); GtkListStore *store = GTK_LIST_STORE( gm_worlds_list_dialog_instance->model_worlds); if (logo) { pix_logo = gm_pixbuf_get_at_size(logo, 32, 32); } else { pix_logo = gm_pixbuf_get_at_size("world.svg", 32, 32); } gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, LOGO_COLUMN, pix_logo, NAME_COLUMN, name, WORLD_COLUMN, world, -1); g_signal_connect(gm_world_options(world), "option_changed", G_CALLBACK(on_gm_worlds_list_dialog_world_option_changed), world); g_free(name); } #define G_WORLDS_LISTS_DIALOG_XML PACKAGE_DATA_DIR "/" PACKAGE \ "/ui/gm-worlds-list.glade" static void gm_worlds_list_dialog_populate_worlds() { GmApp *app = gm_app_instance(); GList *worlds = gm_app_worlds(app); GList *item; GmWorld *world; for (item = worlds; item; item = item->next) { world = (GmWorld *)(item->data); gm_worlds_list_dialog_add_world(world); } g_list_free(worlds); } static void gm_worlds_list_dialog_create_tree_view_worlds() { GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeView *tree_view; GtkTreeModel *model; model = GTK_TREE_MODEL(gtk_list_store_new(N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER)); tree_view = GTK_TREE_VIEW(gm_worlds_list_dialog_widget("tree_view_worlds")); gtk_tree_view_set_model(tree_view, model); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(tree_view), GTK_SELECTION_MULTIPLE); renderer = gtk_cell_renderer_pixbuf_new(); column = gtk_tree_view_column_new_with_attributes(_("Logo"), renderer, "pixbuf", LOGO_COLUMN, NULL); gtk_tree_view_column_set_min_width(column, 40); gtk_tree_view_append_column(tree_view, column); renderer = gtk_cell_renderer_text_new(); column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "markup", NAME_COLUMN, NULL); gtk_tree_view_append_column(tree_view, column); gm_worlds_list_dialog_instance->tree_view_worlds = tree_view; gm_worlds_list_dialog_instance->model_worlds = model; gm_worlds_list_dialog_populate_worlds(); } void gm_worlds_list_dialog_run() { GladeXML *xml; if (gm_worlds_list_dialog_instance) { gtk_widget_show(gm_worlds_list_dialog_instance->dialog); gtk_window_present(GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); return; } gm_worlds_list_dialog_instance = g_new0(GmWorldsListDialog, 1); xml = glade_xml_new(G_WORLDS_LISTS_DIALOG_XML, "gm_worlds_list_dialog", NULL); gm_worlds_list_dialog_instance->xml = xml; gm_worlds_list_dialog_create_tree_view_worlds(); glade_xml_signal_connect(xml, "on_button_delete_clicked", G_CALLBACK(on_gm_worlds_list_dialog_button_delete_clicked)); glade_xml_signal_connect(xml, "on_button_new_clicked", G_CALLBACK(on_gm_worlds_list_dialog_button_new_clicked)); glade_xml_signal_connect(xml, "on_button_modify_clicked", G_CALLBACK(on_gm_worlds_list_dialog_button_modify_clicked)); glade_xml_signal_connect(xml, "on_button_duplicate_clicked", G_CALLBACK(on_gm_worlds_list_dialog_button_connect_clicked)); glade_xml_signal_connect(xml, "on_button_connect_clicked", G_CALLBACK(on_gm_worlds_list_dialog_button_connect_clicked)); glade_xml_signal_connect(xml, "on_tree_view_worlds_key_press", G_CALLBACK(on_gm_worlds_list_dialog_tree_view_worlds_key_press)); gm_worlds_list_dialog_instance->dialog = gm_worlds_list_dialog_widget("gm_worlds_list_dialog"); g_signal_connect(gm_app_instance(), "world_added", G_CALLBACK(on_gm_worlds_list_dialog_app_world_added), NULL); g_signal_connect(gm_app_instance(), "world_removed", G_CALLBACK(on_gm_worlds_list_dialog_app_world_removed), NULL); gtk_window_set_icon(GTK_WINDOW(gm_worlds_list_dialog_instance->dialog), gm_pixbuf_get("world.svg")); gtk_widget_show(gm_worlds_list_dialog_instance->dialog); g_signal_connect(gm_worlds_list_dialog_instance->dialog, "response", G_CALLBACK(on_gm_worlds_list_dialog_response), NULL); } static void gm_worlds_list_dialog_delete_selected_worlds() { GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds; GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds; GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); GtkTreeIter iter; GList *paths = gtk_tree_selection_get_selected_rows(selection, &model); GList *refs = NULL; GList *node = NULL; gchar *message; gpointer proxy = g_object_newv(G_TYPE_OBJECT, 0, NULL); GmWorld *world; for (node = paths; node; node = node->next) { refs = g_list_append(refs, gtk_tree_row_reference_new_proxy(proxy, model, node->data)); gtk_tree_path_free(node->data); } g_list_free(paths); if (refs) { for (node = refs; node; node = node->next) { GtkTreePath *path = gtk_tree_row_reference_get_path(node->data); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_model_get(model, &iter, WORLD_COLUMN, &world, -1); if (!(world && gm_world_loaded(world))) { gtk_list_store_remove(GTK_LIST_STORE(model), &iter); gm_app_remove_world(gm_app_instance(), world); } else { message = g_strdup_printf(_ ("Can't remove the world %s because it is loaded. " "First close the world and then try again."), gm_world_name(world)); gm_error_dialog(message, GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); g_free(message); } gtk_tree_row_reference_deleted(proxy, path); gtk_tree_path_free(path); gtk_tree_row_reference_free(node->data); } } else { gm_error_dialog(_("You first need to select a world to delete."), GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); } g_list_free(refs); g_object_unref(proxy); } void gm_worlds_list_dialog_modify_world() { GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds; GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds; GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); GtkTreeIter iter; GList *first_path = gtk_tree_selection_get_selected_rows(selection, &model); GmWorld *world; if (first_path) { gtk_tree_model_get_iter(model, &iter, first_path->data); gtk_tree_model_get(model, &iter, WORLD_COLUMN, &world, -1); gm_world_properties_dialog_run(world); } else { gm_error_dialog(_("You first need to select a world to modify."), GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); } g_list_free(first_path); } GList * gm_worlds_list_dialog_selected_path() { GtkTreeView *tree_view = gm_worlds_list_dialog_instance->tree_view_worlds; GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds; GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view); return gtk_tree_selection_get_selected_rows(selection, &model); } GmWorld * gm_worlds_list_dialog_selected_world() { GtkTreeIter iter; GList *first_path = gm_worlds_list_dialog_selected_path(); GmWorld *world = NULL; if (first_path) { gtk_tree_model_get_iter(gm_worlds_list_dialog_instance->model_worlds, &iter, first_path->data); gtk_tree_model_get(gm_worlds_list_dialog_instance->model_worlds, &iter, WORLD_COLUMN, &world, -1); } g_list_free(first_path); return world; } gboolean gm_worlds_list_dialog_find(GmWorld *world, GtkTreeIter *iter) { GtkTreeModel *model = gm_worlds_list_dialog_instance->model_worlds; GmWorld *list_world; if (gtk_tree_model_get_iter_first(model, iter)) { do { gtk_tree_model_get(model, iter, WORLD_COLUMN, &list_world, -1); if (world == list_world) { return TRUE; } } while (gtk_tree_model_iter_next(model, iter)); } return FALSE; } // Callbacks void on_gm_worlds_list_dialog_response(GtkDialog *dialog, gint response, gpointer user_data) { g_object_unref(gm_worlds_list_dialog_instance->xml); gtk_widget_destroy(gm_worlds_list_dialog_instance->dialog); g_free(gm_worlds_list_dialog_instance); gm_worlds_list_dialog_instance = NULL; } void on_gm_worlds_list_dialog_button_delete_clicked(GtkButton *button, gpointer user_data) { gm_worlds_list_dialog_delete_selected_worlds(); } void on_gm_worlds_list_dialog_tree_view_worlds_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { switch (event->keyval) { case GDK_D: case GDK_d: gm_worlds_list_dialog_delete_selected_worlds(); break; case GDK_O: case GDK_o: break; case GDK_N: case GDK_n: gm_world_properties_dialog_run_new(NULL); break; case GDK_M: case GDK_m: gm_worlds_list_dialog_modify_world(); break; } } void on_gm_worlds_list_dialog_button_new_clicked(GtkButton *button, gpointer user_data) { gm_world_properties_dialog_run_new(NULL); } void on_gm_worlds_list_dialog_button_modify_clicked(GtkButton *button, gpointer user_data) { gm_worlds_list_dialog_modify_world(); } void on_gm_worlds_list_dialog_button_duplicate_clicked(GtkButton *button, gpointer user_data) { GmWorld *world = gm_worlds_list_dialog_selected_world(); GmWorld *new_world; if (world) { // now duplicate the world new_world = gm_world_dup(world); // Yeah we got some world, now show the props! gm_world_properties_dialog_run_new(new_world); } else { gm_error_dialog( _("You first need to select a world to duplicate."), GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); } } void on_gm_worlds_list_dialog_button_connect_clicked(GtkButton *button, gpointer user_data) { GList *first_path = gm_worlds_list_dialog_selected_path(); GList *path; GmWorld *world; GtkTreeIter iter; if (first_path) { for (path = first_path; path; path = path->next) { gtk_tree_model_get_iter( gm_worlds_list_dialog_instance->model_worlds, &iter, first_path->data); gtk_tree_model_get(gm_worlds_list_dialog_instance->model_worlds, &iter, WORLD_COLUMN, &world, -1); gm_world_load(world); } } else { gm_error_dialog( _("You first need to select a world to connect to."), GTK_WINDOW(gm_worlds_list_dialog_instance->dialog)); } g_list_free(first_path); } void on_gm_worlds_list_dialog_app_world_added(GmApp *app, GmWorld *world, gpointer user_data) { gm_worlds_list_dialog_add_world(world); } void on_gm_worlds_list_dialog_app_world_removed(GmApp *app, GmWorld *world, gpointer user_data) { GtkTreeIter iter; if (gm_worlds_list_dialog_find(world, &iter)) { gtk_list_store_remove(GTK_LIST_STORE( gm_worlds_list_dialog_instance->model_worlds), &iter); } } void on_gm_worlds_list_dialog_world_option_changed(GmOptions *options, const gchar *key, GmWorld *world) { GtkTreeIter iter; GtkListStore *store = GTK_LIST_STORE(gm_worlds_list_dialog_instance->model_worlds); gchar *text; const gchar *logo; GdkPixbuf *pix_logo; if (!gm_worlds_list_dialog_find(world, &iter)) { return; } if (strcmp(key, "name") == 0 || strcmp(key, "player_name") == 0 || strcmp(key, "host") == 0) { text = gm_worlds_list_dialog_world_text(world); gtk_list_store_set(store, &iter, NAME_COLUMN, text, -1); g_free(text); } else if (strcmp(key, "logo")) { logo = gm_options_get(options, "logo"); if (logo) { pix_logo = gm_pixbuf_get_at_size(logo, 32, 32); } else { pix_logo = gm_pixbuf_get_at_size("world.svg", 32, 32); } gtk_list_store_set(store, &iter, LOGO_COLUMN, pix_logo, -1); } }