/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */ /* Copyright (C) 2004 Carlos Garnacho Parro. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * Authors: Carlos Garnacho Parro */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include "address-list.h" #include "gst-tool.h" #include "gst-filter.h" #include "callbacks.h" extern GstTool *tool; struct _GstAddressListPrivate { GtkTreeView *list; GtkTreeViewColumn *column; GtkButton *add_button; GtkButton *delete_button; guint type; GstAddressListSaveFunc save_func; gpointer save_func_data; }; static void gst_address_list_class_init (GstAddressListClass *class); static void gst_address_list_init (GstAddressList *list); static void gst_address_list_finalize (GObject *object); static void gst_address_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_address_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void save_address_data (GstAddressList *list); static void setup_treeview (GstAddressList *list); static void on_element_deleted (GtkWidget *widget, gpointer data); static void on_element_added (GtkWidget *widget, gpointer data); static void on_editing_canceled (GtkCellRenderer *renderer, gpointer data); static void on_editing_started (GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, GstAddressList *list); static void on_editing_done (GtkCellRenderer *renderer, const gchar *path_string, const gchar *new_text, gpointer data); GtkActionEntry address_list_popup_menu_items [] = { { "Add", GTK_STOCK_ADD, N_("_Add"), NULL, NULL, G_CALLBACK (on_element_added) }, { "Delete", GTK_STOCK_DELETE, N_("_Delete"), NULL, NULL, G_CALLBACK (on_element_deleted) } }; const gchar *address_list_ui_description = "" " " " " " " " " ""; enum { PROP_0, PROP_LIST_WIDGET, PROP_TYPE, PROP_ADD_BUTTON, PROP_DELETE_BUTTON }; G_DEFINE_TYPE (GstAddressList, gst_address_list, G_TYPE_OBJECT); GType gst_address_type_get_type (void) { static GType etype = 0; if (!etype) { static GEnumValue values[] = { { GST_ADDRESS_TYPE_IP, "GST_ADDRESS_TYPE_IP", "IP" }, { GST_ADDRESS_TYPE_DOMAIN, "GST_ADDRESS_TYPE_DOMAIN", "domain" } }; etype = g_enum_register_static ("GstAddressType", values); } return etype; } static void gst_address_list_class_init (GstAddressListClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); object_class->set_property = gst_address_list_set_property; object_class->get_property = gst_address_list_get_property; object_class->finalize = gst_address_list_finalize; g_object_class_install_property (object_class, PROP_TYPE, g_param_spec_enum ("list-type", "List type", "Type of addresses that the list will contain", GST_TYPE_ADDRESS_TYPE, GST_ADDRESS_TYPE_IP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_LIST_WIDGET, g_param_spec_object ("list-widget", "List widget", "TreeView that will display the list", GTK_TYPE_TREE_VIEW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_ADD_BUTTON, g_param_spec_object ("add-button", "Add button", "Button for adding addresses", GTK_TYPE_BUTTON, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DELETE_BUTTON, g_param_spec_object ("delete-button", "delete button", "Button for deleting addresses", GTK_TYPE_BUTTON, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } static void gst_address_list_init (GstAddressList *list) { g_return_if_fail (GST_IS_ADDRESS_LIST (list)); list->_priv = g_new0 (GstAddressListPrivate, 1); list->_priv->type = 0; } static void gst_address_list_finalize (GObject *object) { GstAddressList *list; g_return_if_fail (GST_IS_ADDRESS_LIST (object)); list = GST_ADDRESS_LIST (object); if (list->_priv) { g_object_unref (list->_priv->list); list->_priv->list = NULL; g_object_unref (list->_priv->add_button); list->_priv->add_button = NULL; g_object_unref (list->_priv->delete_button); list->_priv->delete_button = NULL; g_free (list->_priv); list->_priv = NULL; } if (G_OBJECT_CLASS (gst_address_list_parent_class)->finalize) (* G_OBJECT_CLASS (gst_address_list_parent_class)->finalize) (object); } static void gst_address_list_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstAddressList *list; g_return_if_fail (GST_IS_ADDRESS_LIST (object)); list = GST_ADDRESS_LIST (object); switch (prop_id) { case PROP_TYPE: list->_priv->type = (GstAddressType) g_value_get_enum (value); break; case PROP_LIST_WIDGET: list->_priv->list = GTK_TREE_VIEW (g_object_ref (g_value_get_object (value))); setup_treeview (list); break; case PROP_ADD_BUTTON: list->_priv->add_button = GTK_BUTTON (g_object_ref (g_value_get_object (value))); g_signal_connect (G_OBJECT (list->_priv->add_button), "clicked", G_CALLBACK (on_element_added), list); break; case PROP_DELETE_BUTTON: list->_priv->delete_button = GTK_BUTTON (g_object_ref (g_value_get_object (value))); g_signal_connect (G_OBJECT (list->_priv->delete_button), "clicked", G_CALLBACK (on_element_deleted), list); break; } } static void gst_address_list_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstAddressList *list; g_return_if_fail (GST_IS_ADDRESS_LIST (object)); list = GST_ADDRESS_LIST (object); switch (prop_id) { case PROP_TYPE: g_value_set_enum (value, list->_priv->type); break; case PROP_LIST_WIDGET: g_value_set_object (value, list->_priv->list); break; case PROP_ADD_BUTTON: g_value_set_object (value, list->_priv->add_button); break; case PROP_DELETE_BUTTON: g_value_set_object (value, list->_priv->delete_button); break; } } static GtkWidget* popup_menu_create (GstAddressList *list) { GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkWidget *popup; action_group = gtk_action_group_new ("MenuActions"); gtk_action_group_set_translation_domain (action_group, NULL); gtk_action_group_add_actions (action_group, address_list_popup_menu_items, G_N_ELEMENTS (address_list_popup_menu_items), list); ui_manager = gtk_ui_manager_new (); gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); if (!gtk_ui_manager_add_ui_from_string (ui_manager, address_list_ui_description, -1, NULL)) return NULL; g_object_set_data (G_OBJECT (list), "ui-manager", ui_manager); popup = gtk_ui_manager_get_widget (ui_manager, "/MainMenu"); return popup; } static void on_list_drag_end (GtkWidget *widget, GdkDragContext *context, gpointer data) { GstAddressList *list = (GstAddressList *) data; save_address_data (list); } static void setup_treeview (GstAddressList *list) { GtkCellRenderer *renderer; GtkTreeModel *model; GstTablePopup *table_popup; GtkTargetEntry target = { "dns", GTK_TARGET_SAME_WIDGET, 0 }; model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN)); gtk_tree_view_set_model (list->_priv->list, model); g_object_unref (model); renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); g_signal_connect (G_OBJECT (renderer), "editing-started", G_CALLBACK (on_editing_started), list); g_signal_connect (G_OBJECT (renderer), "editing-canceled", G_CALLBACK (on_editing_canceled), list); g_signal_connect (G_OBJECT (renderer), "edited", G_CALLBACK (on_editing_done), list); list->_priv->column = gtk_tree_view_column_new_with_attributes ("Address", renderer, "text", 0, NULL); gtk_tree_view_insert_column (list->_priv->list, list->_priv->column, -1); table_popup = g_new0 (GstTablePopup, 1); table_popup->setup = NULL; table_popup->properties = NULL; table_popup->popup = popup_menu_create (list); g_signal_connect (G_OBJECT (list->_priv->list), "button-press-event", G_CALLBACK (on_table_button_press), table_popup); g_signal_connect (G_OBJECT (list->_priv->list), "popup_menu", G_CALLBACK (on_table_popup_menu), table_popup); g_signal_connect (G_OBJECT (list->_priv->list), "drag-end", G_CALLBACK (on_list_drag_end), list); } static gboolean check_address (GstAddressList *list, const gchar *text) { gint type; if (list->_priv->type != GST_ADDRESS_TYPE_IP) return TRUE; type = gst_filter_check_ip_address (text); if (type == GST_ADDRESS_IPV4 || type == GST_ADDRESS_IPV6) return TRUE; return FALSE; } static void on_editable_activate (GtkWidget *widget, GstAddressList *list) { gchar *text; text = (gchar *) gtk_entry_get_text (GTK_ENTRY (widget)); if (!check_address (list, text)) g_signal_stop_emission_by_name (widget, "activate"); } static void on_editing_started (GtkCellRenderer *renderer, GtkCellEditable *editable, gchar *path, GstAddressList *list) { if (GTK_IS_ENTRY (editable)) { g_signal_connect (G_OBJECT (editable), "activate", G_CALLBACK (on_editable_activate), list); if (list->_priv->type == GST_ADDRESS_TYPE_IP) gst_filter_init (GTK_ENTRY (editable), GST_FILTER_IP); } } static void on_editing_canceled (GtkCellRenderer *renderer, gpointer data) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GstAddressList *list; gboolean is_new_row; list = (GstAddressList *) data; selection = gtk_tree_view_get_selection (list->_priv->list); if (!gtk_tree_selection_get_selected (selection, &model, &iter)) return; gtk_tree_model_get (model, &iter, 1, &is_new_row, -1); if (is_new_row) gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } static void save_address_data (GstAddressList *list) { GtkTreeModel *model; GtkTreeIter iter; gboolean valid; GList *l = NULL; gchar *str; g_return_if_fail (list->_priv->save_func != NULL); model = gtk_tree_view_get_model (list->_priv->list); valid = gtk_tree_model_get_iter_first (model, &iter); while (valid) { gtk_tree_model_get (model, &iter, 0, &str, -1); l = g_list_prepend (l, str); valid = gtk_tree_model_iter_next (model, &iter); } l = g_list_reverse (l); (list->_priv->save_func) (l, list->_priv->save_func_data); } static void on_editing_done (GtkCellRenderer *renderer, const gchar *path_string, const gchar *new_text, gpointer data) { GtkTreeModel *model; GtkTreePath *path; GtkTreeIter iter; GstAddressList *list; gboolean is_new_row; list = (GstAddressList *) data; model = gtk_tree_view_get_model (list->_priv->list); path = gtk_tree_path_new_from_string (path_string); gtk_tree_model_get_iter (model, &iter, path); if (!check_address (list, new_text)) { gtk_tree_model_get (model, &iter, 1, &is_new_row, -1); if (is_new_row) gtk_list_store_remove (GTK_LIST_STORE (model), &iter); } else { gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, new_text, 1, FALSE, -1); save_address_data (list); } } static void on_element_deleted (GtkWidget *widget, gpointer data) { GstAddressList *list; GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; list = (GstAddressList *) data; selection = gtk_tree_view_get_selection (list->_priv->list); if (gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_list_store_remove (GTK_LIST_STORE (model), &iter); save_address_data (list); } static void on_element_added (GtkWidget *widget, gpointer data) { GstAddressList *list; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; list = (GstAddressList *) data; model = gtk_tree_view_get_model (list->_priv->list); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, _("Type address"), 1, TRUE, -1); gtk_widget_grab_focus (GTK_WIDGET (list->_priv->list)); path = gtk_tree_model_get_path (model, &iter); gtk_tree_view_set_cursor (list->_priv->list, path, list->_priv->column, TRUE); gtk_tree_path_free (path); } void gst_address_list_add_address (GstAddressList *list, const gchar *address) { GtkTreeModel *model; GtkTreeIter iter; g_return_if_fail (list != NULL); g_return_if_fail (address != NULL); /* FIXME: check address type */ model = gtk_tree_view_get_model (list->_priv->list); gtk_list_store_append (GTK_LIST_STORE (model), &iter); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, address, 1, FALSE, -1); } GSList* gst_address_list_get_list (GstAddressList *list) { GtkTreeModel *model; GtkTreeIter iter; GSList *l = NULL; gboolean valid; gchar *address; g_return_val_if_fail (list != NULL, NULL); model = gtk_tree_view_get_model (list->_priv->list); valid = gtk_tree_model_get_iter_first (model, &iter); while (valid) { gtk_tree_model_get (model, &iter, 0, &address, -1); l = g_slist_append (l, address); valid = gtk_tree_model_iter_next (model, &iter); } return l; } void gst_address_list_clear (GstAddressList *list) { GtkTreeModel *model; model = gtk_tree_view_get_model (list->_priv->list); gtk_list_store_clear (GTK_LIST_STORE (model)); } GstAddressList* gst_address_list_new (GtkTreeView *treeview, GtkButton *add_button, GtkButton *delete_button, GstAddressType list_type) { GstAddressList *list; list = g_object_new (GST_TYPE_ADDRESS_LIST, "list-widget", GTK_WIDGET (treeview), "list-type", list_type, "add-button", add_button, "delete-button", delete_button, NULL); return list; } void gst_address_list_set_save_func (GstAddressList *address_list, GstAddressListSaveFunc save_func, gpointer save_func_data) { g_return_if_fail (address_list != NULL); address_list->_priv->save_func = save_func; address_list->_priv->save_func_data = save_func_data; }