/* * Copyright (C) 2013 - Juan Ferrer Toribio * * 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 3 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, see . */ #include "glade-vn.h" #include "glade-db-model-editor.h" /* * Contents of this file: * definition of the custom property editors for the DbModel properties. * definition of the SQL statement editor for the "sql" property of the * DbModel. * the definition of the param-related properties can be found at their * own file glade-db-model-links.c and glade-db-model-batch.c */ #ifdef _HAVE_GTKSOURCEVIEW #include #include #include #include #endif #define NEW_SQL _("New SQL statement") //+++++++++++++++++++++++++++++++++++++++++++++++++++ SQL Editor Property typedef struct { GladeEditorProperty parent; GtkWidget * button; GtkWidget * entry; gint width; gint height; } GladeEPropSql; GLADE_MAKE_EPROP (GladeEPropSql, glade_eprop_sql) #define GLADE_TYPE_EPROP_SQL (glade_eprop_sql_get_type()) #define GLADE_EPROP_SQL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_SQL, GladeEPropSql)) #define GLADE_EPROP_SQL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_SQL, GladeEPropSqlClass)) #define GLADE_IS_EPROP_SQL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_SQL)) #define GLADE_IS_EPROP_SQL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_SQL)) #define GLADE_EPROP_SQL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GLADE_EPROP_SQL, GladeEPropSqlClass)) static void glade_eprop_sql_show_dialog (GtkButton * button, GladeEditorProperty * eprop) { gpointer text, buffer; const gchar * sql; GladeEPropSql * obj = GLADE_EPROP_SQL (eprop); PangoFontDescription * font; GtkWidget * scroll; GladeProperty * p = glade_editor_property_get_property (eprop); GtkDialog * dialog = GTK_DIALOG (gtk_dialog_new_with_buttons (_("SQL Editor") ,GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (eprop))) ,GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,_("OK"), GTK_RESPONSE_OK ,_("Clear"), GTK_RESPONSE_REJECT ,_("Cancel"), GTK_RESPONSE_CANCEL ,NULL )); gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK); gtk_window_set_default_size (GTK_WINDOW (dialog), obj->width, obj->height); scroll = gtk_scrolled_window_new (gtk_adjustment_new (0,0,0,0,0,0), gtk_adjustment_new (0,0,0,0,0,0)); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN); gtk_widget_set_margin_top (scroll, 6); gtk_widget_set_margin_bottom (scroll, 6); gtk_widget_set_margin_start (scroll, 6); gtk_widget_set_margin_end (scroll, 6); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (dialog)), scroll, TRUE, TRUE, 6); #ifdef _HAVE_GTKSOURCEVIEW GtkSourceLanguageManager * lm = gtk_source_language_manager_new (); GtkSourceLanguage * lang = gtk_source_language_manager_get_language (lm, "sql"); text = gtk_source_view_new (); gtk_source_view_set_tab_width (text, 4); gtk_source_view_set_show_line_numbers (text, TRUE); gtk_source_view_set_highlight_current_line (text, TRUE); buffer = gtk_text_view_get_buffer (text); gtk_source_buffer_set_language (buffer, lang); gtk_source_buffer_set_highlight_matching_brackets (buffer, TRUE); #else text = gtk_text_view_new (); buffer = gtk_text_view_get_buffer (text); #endif font = pango_font_description_from_string ("Monospace"); gtk_widget_override_font (text, font); pango_font_description_free (font); if ((sql = g_value_get_string (glade_property_inline_value (p)))) gtk_text_buffer_set_text (buffer, sql, -1); gtk_container_add (GTK_CONTAINER (scroll), text); gtk_widget_show_all (scroll); switch (gtk_dialog_run (dialog)) { case GTK_RESPONSE_OK: { GValue val = G_VALUE_INIT; GtkTextIter * start = g_new (GtkTextIter, 1), * end = g_new (GtkTextIter, 1); g_value_init (&val, G_TYPE_STRING); gtk_text_buffer_get_bounds (buffer, start, end); sql = gtk_text_buffer_get_text (buffer, start, end, TRUE); g_value_set_string (&val, sql); glade_command_set_property_value (p, &val); g_value_unset (&val); g_free (start); g_free (end); break; } case GTK_RESPONSE_REJECT: { GValue val = G_VALUE_INIT; g_value_init (&val, G_TYPE_STRING); g_value_set_string (&val, ""); glade_command_set_property_value (p, &val); g_value_unset (&val); break; } case GTK_RESPONSE_CANCEL: default: break; } obj->width = gtk_widget_get_allocated_width (GTK_WIDGET (dialog)); obj->height = gtk_widget_get_allocated_height (GTK_WIDGET (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog)); } static void glade_eprop_sql_entry_text_changed (GtkEntry * entry, GladeEditorProperty * eprop) { const gchar * text = gtk_entry_get_text (entry); GladeProperty * p = glade_editor_property_get_property (eprop); if (text) { GValue val = G_VALUE_INIT; g_value_init (&val, G_TYPE_STRING); g_value_set_string (&val, text); glade_command_set_property_value (p, &val); g_value_unset (&val); } } static GtkWidget * glade_eprop_sql_create_input (GladeEditorProperty * eprop) { GladeEPropSql * obj = GLADE_EPROP_SQL (eprop); GtkWidget * box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); obj->entry = gtk_entry_new (); gtk_widget_set_hexpand (obj->entry, TRUE); g_signal_connect (obj->entry, "changed", G_CALLBACK (glade_eprop_sql_entry_text_changed), obj); gtk_container_add (GTK_CONTAINER (box), obj->entry); obj->button = gtk_button_new_with_label ("..."); g_signal_connect (obj->button, "clicked", G_CALLBACK (glade_eprop_sql_show_dialog), obj); gtk_widget_set_tooltip_text (obj->button, _("Open the SQL Editor")); gtk_container_add (GTK_CONTAINER (box), obj->button); gtk_widget_show_all (box); obj->width = 750; obj->height = 550; return box; } static void glade_eprop_sql_load (GladeEditorProperty * eprop, GladeProperty * property) { const gchar * sql; GladeEPropSql * obj = GLADE_EPROP_SQL (eprop); GladeEditorPropertyClass * parent_class = g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)); parent_class->load (eprop, property); if (!property) return; if ((sql = g_value_get_string (glade_property_inline_value (property)))) gtk_entry_set_text (GTK_ENTRY (obj->entry), sql); else gtk_entry_set_text (GTK_ENTRY (obj->entry), ""); } static void glade_eprop_sql_finalize (GObject * object) { GObjectClass * parent_class = g_type_class_peek_parent (G_OBJECT_GET_CLASS (object)); G_OBJECT_CLASS (parent_class)->finalize (object); } //++++++++++++++++++++++++++++ Structure and prototypes for Links and Batch typedef struct { GladeEditorProperty parent; GtkTreeView * view; gchar * path; } GladeListEProp; void param_col_cell_data (GtkTreeViewColumn * view, GtkCellRenderer * cell, GtkTreeModel * model, GtkTreeIter * iter, gpointer data); static void glade_list_eprop_add_param_column (GladeListEProp * obj); static void glade_list_eporp_on_string_col_edited (GtkCellRendererText * cell, gchar * path, const gchar * text, GladeEditorProperty * eprop); static void glade_list_eprop_create_input (GladeListEProp * obj, GtkWidget * box, gchar * string); //+++++++++++++++++++++++++++++++++++++++++++++++++++ Links Editor Property typedef GladeListEProp GladeEPropLinks; GLADE_MAKE_EPROP (GladeEPropLinks, glade_eprop_links) #define GLADE_TYPE_EPROP_LINKS (glade_eprop_links_get_type ()) #define GLADE_EPROP_LINKS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_LINKS, GladeEPropLinks)) #define GLADE_EPROP_LINKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_LINKS, GladeEPropLinksClass)) #define GLADE_IS_EPROP_LINKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_LINKS)) #define GLADE_IS_EPROP_LINKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_LINKS)) #define GLADE_EPROP_LINKS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GLADE_EPROP_LINKS, GladeEPropLinksClass)) enum { LINKS_FIELD_COL ,LINKS_PARAM_COL ,LINKS_LINKED_COL ,LINKS_N_COLS }; static void linked_col_cell_data (GtkTreeViewColumn * view, GtkCellRenderer * cell, GtkTreeModel * model, GtkTreeIter * iter, gpointer data) { gboolean val; gtk_tree_model_get (model, iter, LINKS_LINKED_COL, &val, -1); gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell), val); } static void glade_eprop_links_on_linked_col_toggled (GtkCellRendererToggle * cell, gchar * path, GladeEditorProperty * eprop) { gboolean val; GtkTreeIter iter; GladeProperty * p = glade_editor_property_get_property (eprop); GladeDbList * list = g_value_get_boxed (glade_property_inline_value (p)); GtkListStore * store = list->list; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path)) return; gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, LINKS_LINKED_COL, &val, -1); gtk_list_store_set (store, &iter, LINKS_LINKED_COL, !val, -1); } static GtkWidget * glade_eprop_links_create_input (GladeEditorProperty * eprop) { GtkCellRenderer * cell; GtkTreeViewColumn * column; GladeEPropLinks * obj = GLADE_EPROP_LINKS (eprop); GtkWidget * box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); glade_list_eprop_create_input ((GladeListEProp *) obj, box, _("Add or remove links")); cell = gtk_cell_renderer_text_new (); g_object_set (cell, "editable", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes (_("Column"), cell, "text", LINKS_FIELD_COL, NULL); gtk_tree_view_column_set_expand (column, TRUE); g_signal_connect (cell, "edited", G_CALLBACK (glade_list_eporp_on_string_col_edited), obj); gtk_tree_view_append_column (obj->view, column); glade_list_eprop_add_param_column (obj); cell = gtk_cell_renderer_toggle_new (); column = gtk_tree_view_column_new_with_attributes (C_("Verb", "Link"), cell, NULL); gtk_tree_view_column_set_cell_data_func (column, cell, linked_col_cell_data, obj, NULL); g_signal_connect (cell, "toggled", G_CALLBACK (glade_eprop_links_on_linked_col_toggled), obj); gtk_tree_view_append_column (obj->view, column); g_object_set (G_OBJECT (box), "height-request", 200, NULL); gtk_widget_show_all (box); return box; } static void glade_eprop_links_finalize (GObject * object) { GladeEPropLinks * obj = GLADE_EPROP_LINKS (object); GObjectClass * parent = g_type_class_peek_parent (GLADE_EPROP_LINKS_GET_CLASS (obj)); parent->finalize (G_OBJECT (obj)); } static void glade_eprop_links_load (GladeEditorProperty * eprop, GladeProperty * property) { GladeDbList * list; GladeEPropLinks * obj = GLADE_EPROP_LINKS (eprop); GladeEditorPropertyClass * parent_class = g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)); parent_class->load (eprop, property); if (!property) return; if ((list = g_value_get_boxed (glade_property_inline_value (property)))) gtk_tree_view_set_model (obj->view, GTK_TREE_MODEL (list->list)); else gtk_tree_view_set_model (obj->view, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Batch Editor Property typedef GladeListEProp GladeEPropBatch; enum { BATCH_ID_COL ,BATCH_PARAM_COL ,BATCH_N_COLS }; GLADE_MAKE_EPROP (GladeEPropBatch, glade_eprop_batch) #define GLADE_TYPE_EPROP_BATCH (glade_eprop_batch_get_type ()) #define GLADE_EPROP_BATCH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_BATCH, GladeEPropBatch)) #define GLADE_EPROP_BATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_BATCH, GladeEPropBatchClass)) #define GLADE_IS_EPROP_BATCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_BATCH)) #define GLADE_IS_EPROP_BATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_BATCH)) #define GLADE_EPROP_BATCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GLADE_EPROP_BATCH, GladeEPropBatchClass)) static GtkWidget * glade_eprop_batch_create_input (GladeEditorProperty * eprop) { GtkCellRenderer * cell; GtkTreeViewColumn * column; GladeEPropBatch * obj = GLADE_EPROP_BATCH (eprop); GtkWidget * box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); glade_list_eprop_create_input ((GladeListEProp *) obj, box, _("Add or remove holders")); cell = gtk_cell_renderer_text_new (); g_object_set (cell, "editable", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes (_("Identifier"), cell, "text", BATCH_ID_COL, NULL); gtk_tree_view_column_set_expand (column, TRUE); g_signal_connect (cell, "edited", G_CALLBACK (glade_list_eporp_on_string_col_edited), obj); gtk_tree_view_append_column (obj->view, column); glade_list_eprop_add_param_column (obj); g_object_set (G_OBJECT (box), "height-request", 200, NULL); gtk_widget_show_all (box); return box; } void glade_eprop_batch_finalize (GObject * object) { GladeEPropBatch * obj = GLADE_EPROP_BATCH (object); GObjectClass * parent = g_type_class_peek_parent (GLADE_EPROP_BATCH_GET_CLASS (obj)); parent->finalize (G_OBJECT (obj)); } static void glade_eprop_batch_load (GladeEditorProperty * eprop, GladeProperty * property) { GladeDbList * list; GladeEPropBatch * obj = GLADE_EPROP_BATCH (eprop); GladeEditorPropertyClass * parent_class = g_type_class_peek_parent (GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)); parent_class->load (eprop, property); if (!property) return; if ((list = g_value_get_boxed (glade_property_inline_value (property)))) gtk_tree_view_set_model (obj->view, GTK_TREE_MODEL (list->list)); else gtk_tree_view_set_model (obj->view, NULL); } //+++++++++++++++++++++++++++++++++++++++ Methods common to Links and Batch void param_col_cell_data (GtkTreeViewColumn * view, GtkCellRenderer * cell, GtkTreeModel * model, GtkTreeIter * iter, gpointer data) { GladeWidget * param; gint col = GLADE_IS_EPROP_LINKS (data) ? LINKS_PARAM_COL : BATCH_PARAM_COL; gtk_tree_model_get (model, iter, col, ¶m, -1); if (param) g_object_set (cell, "text", glade_widget_get_name (param), NULL); else g_object_set (cell, "text", "", NULL); } static void glade_list_eprop_on_param_col_clicked (GtkEntry * entry, GtkEntryIconPosition icon_pos, GdkEvent * event, GladeEditorProperty * eprop) { GtkTreeIter iter; GladeProperty * p = glade_editor_property_get_property (eprop); GladeWidget * widget = glade_property_get_widget (p); GladeProject * project = glade_widget_get_project (widget); GtkListStore * store = ((GladeDbList *) g_value_get_boxed (glade_property_inline_value (p)))->list; gchar * path = ((GladeListEProp *) eprop)->path; gint col = GLADE_IS_EPROP_LINKS (eprop) ? LINKS_PARAM_COL : BATCH_PARAM_COL; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path)) return; gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, col, &widget, -1); if (glade_editor_property_show_object_dialog (project, _("Select a GvnParam"), NULL, GVN_TYPE_PARAM, NULL, &widget)) { if (widget) gtk_list_store_set (store, &iter, col, widget, -1); else gtk_list_store_set (store, &iter, col, NULL, -1); } } static gboolean glade_list_eprop_on_param_key_pressed (GtkEntry * entry, GdkEventKey * event, GladeEditorProperty * eprop) { if (event->keyval == GDK_KEY_Return) { glade_list_eprop_on_param_col_clicked (entry, 0, NULL, eprop); return TRUE; } else if (event->keyval == GDK_KEY_Delete) { GtkTreeIter iter; gchar * path = ((GladeListEProp *) eprop)->path; GladeProperty * p = glade_editor_property_get_property (eprop); GtkListStore * store = ((GladeDbList *) g_value_get_boxed (glade_property_inline_value (p)))->list; if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path)) { gint col = GLADE_IS_EPROP_LINKS (eprop) ? LINKS_PARAM_COL : BATCH_PARAM_COL; gtk_list_store_set (store, &iter, col, NULL, -1); return TRUE; } } return FALSE; } static void glade_list_eporp_on_param_col_editing_started (GtkCellRendererText * cell, GtkEntry * entry, gchar * path, GladeEditorProperty * eprop) { GladeListEProp * obj = (GladeListEProp *) eprop; if (GTK_IS_ENTRY (entry)) { GList * n; gboolean have_params = FALSE; GladeProperty * p = glade_editor_property_get_property (eprop); GladeProject * project = glade_widget_get_project (glade_property_get_widget (p)); GList * objects = (GList *) glade_project_get_objects (project); for (n = objects; n; n = n->next) if ((have_params = GVN_IS_PARAM (n->data))) break; if (have_params) { g_object_set (entry ,"secondary-icon-name", "content-loading-symbolic" ,"secondary-icon-sensitive", TRUE ,"secondary-icon-tooltip-text", _("Select the parameter from a list") ,NULL); if (obj->path) g_free (obj->path); obj->path = g_strdup (path); g_signal_connect (entry, "icon-press", G_CALLBACK (glade_list_eprop_on_param_col_clicked), eprop); g_signal_connect (entry, "key-press-event", G_CALLBACK (glade_list_eprop_on_param_key_pressed), eprop); } else { g_object_set (entry ,"secondary-icon-name", "dialog-warning-symbolic" ,"secondary-icon-sensitive", FALSE ,"secondary-icon-tooltip-text", _("You need to create at least " "one GvnParam or derived object") ,NULL); g_signal_handlers_disconnect_by_data (entry, eprop); } g_object_set (entry, "editable", FALSE, NULL); } } static void glade_list_eprop_add_param_column (GladeListEProp * obj) { GtkTreeViewColumn * column; GtkCellRenderer * cell = gtk_cell_renderer_text_new (); g_object_set (cell, "editable", TRUE, NULL); column = gtk_tree_view_column_new_with_attributes (_("Param"), cell, NULL); gtk_tree_view_column_set_cell_data_func (column, cell, param_col_cell_data, obj, NULL); gtk_tree_view_column_set_expand (column, TRUE); g_signal_connect (cell, "editing-started", G_CALLBACK (glade_list_eporp_on_param_col_editing_started), obj); gtk_tree_view_append_column (obj->view, column); } static void glade_list_eporp_on_string_col_edited (GtkCellRendererText * cell, gchar * path, const gchar * text, GladeEditorProperty * eprop) { GtkTreeIter iter; gint col = GLADE_IS_EPROP_LINKS (eprop) ? LINKS_FIELD_COL : BATCH_ID_COL; GladeProperty * p = glade_editor_property_get_property (eprop); GladeDbList * list = g_value_get_boxed (glade_property_inline_value (p)); GtkListStore * store = list->list; if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path)) return; gtk_list_store_set (store, &iter, col, text, -1); } static void glade_widget_on_remove_widget (GladeProject * project, GladeWidget * widget, GtkListStore * store) { if (g_type_is_a (G_OBJECT_TYPE (glade_widget_get_object (widget)), GVN_TYPE_PARAM)) { GtkTreeIter iter; GtkTreeModel * m = GTK_TREE_MODEL (store); if (gtk_tree_model_get_iter_first (m, &iter)) do { gint col = 1; // XXX LINKS_PARAM_COL and BATCH_PARAM_COL GladeWidget * param; gtk_tree_model_get (m, &iter, col, ¶m, -1); if (param == widget) gtk_list_store_set (store, &iter, col, NULL, -1); } while (gtk_tree_model_iter_next (m, &iter)); } } static void glade_list_eprop_on_add_clicked (GtkButton * button, GladeListEProp * obj) { GtkTreeIter iter; GtkTreePath * path; GladeDbList * list; GtkListStore * store; GladeProperty * p = glade_editor_property_get_property (GLADE_EDITOR_PROPERTY (obj)); if (!(list = g_value_get_boxed (glade_property_inline_value (p)))) { list = g_new (GladeDbList, 1); if (GLADE_IS_EPROP_LINKS (obj)) list->list = gtk_list_store_new (LINKS_N_COLS, G_TYPE_STRING, GLADE_TYPE_WIDGET, G_TYPE_BOOLEAN); else list->list = gtk_list_store_new (BATCH_N_COLS, G_TYPE_STRING, GLADE_TYPE_WIDGET); glade_property_set (p, list); g_signal_connect (glade_widget_get_project (glade_property_get_widget (p)), "remove-widget", G_CALLBACK (glade_widget_on_remove_widget), list->list); } store = list->list; gtk_tree_view_set_model (obj->view, GTK_TREE_MODEL (store)); gtk_list_store_append (store, &iter); path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); gtk_tree_view_scroll_to_cell (obj->view, path, NULL, FALSE, 0, 0); gtk_tree_view_set_cursor (obj->view, path, NULL, TRUE); gtk_widget_grab_focus (GTK_WIDGET (obj->view)); gtk_tree_path_free (path); } static void glade_list_eprop_on_remove_clicked (GtkButton * button, GladeListEProp * obj) { GtkTreeIter iter; GtkListStore * store; GtkTreeSelection * selection = gtk_tree_view_get_selection (obj->view); GladeProperty * p; if (!gtk_tree_selection_get_selected (selection, (GtkTreeModel **) &store, &iter)) return; p = glade_editor_property_get_property (GLADE_EDITOR_PROPERTY (obj)); gtk_list_store_remove (store, &iter); if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) { gtk_tree_view_set_model (obj->view, NULL); glade_command_set_property (p, NULL); g_signal_handlers_disconnect_by_func (glade_widget_get_project (glade_property_get_widget (p)), glade_widget_on_remove_widget, store); } } static gboolean glade_list_eprop_on_view_key_press (GtkWidget * treeview, GdkEventKey * event, GladeListEProp * obj) { if (event->keyval == GDK_KEY_Delete) { glade_list_eprop_on_remove_clicked (NULL, obj); return TRUE; } else if ((event->state & GDK_CONTROL_MASK) != 0 && (event->keyval == GDK_KEY_n || event->keyval == GDK_KEY_N)) { glade_list_eprop_on_add_clicked (NULL, obj); return TRUE; } return FALSE; } static void glade_list_eprop_create_input (GladeListEProp * obj, GtkWidget * box, gchar * string) { GtkWidget * scroll, * button, * label, * hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4); label = gtk_label_new (string); gtk_label_set_use_markup (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5); gtk_misc_set_padding (GTK_MISC (label), 2, 4); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (glade_list_eprop_on_add_clicked), obj); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); button = gtk_button_new (); gtk_button_set_image (GTK_BUTTON (button), gtk_image_new_from_icon_name ("list-remove-symbolic", GTK_ICON_SIZE_BUTTON)); g_signal_connect (button, "clicked", G_CALLBACK (glade_list_eprop_on_remove_clicked), obj); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (box), hbox, FALSE, FALSE, 0); scroll = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (box), scroll, TRUE, TRUE, 0); obj->view = GTK_TREE_VIEW (gtk_tree_view_new ()); g_signal_connect (obj->view, "key-press-event", G_CALLBACK (glade_list_eprop_on_view_key_press), obj); gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (obj->view)); } //++++++++++++++++++++++++++++++++++++++++++++++++++ DbModel Widget Adaptor GladeEditorProperty * glade_db_model_create_eprop (GladeWidgetAdaptor * adaptor, GladePropertyClass * klass, gboolean use_command) { GladeEditorProperty * eprop; const gchar * prop_id = glade_property_class_id (klass); if (!g_strcmp0 (prop_id, "sql")) eprop = g_object_new (GLADE_TYPE_EPROP_SQL, "property-class", klass, "use-command", use_command, NULL); else if (!g_strcmp0 (prop_id, "links")) eprop = g_object_new (GLADE_TYPE_EPROP_LINKS, "property-class", klass, "use-command", use_command, NULL); else if (!g_strcmp0 (prop_id, "batch")) eprop = g_object_new (GLADE_TYPE_EPROP_BATCH, "property-class", klass, "use-command", use_command, NULL); else eprop = GWA_GET_CLASS (G_TYPE_OBJECT)->create_eprop (adaptor, klass, use_command); return eprop; } GladeEditable * glade_db_model_create_editable (GladeWidgetAdaptor * adaptor, GladeEditorPageType type) { GladeEditable * editable = GWA_GET_CLASS (G_TYPE_OBJECT)->create_editable (adaptor, type); if (type == GLADE_PAGE_GENERAL) return GLADE_EDITABLE (glade_model_editor_new (adaptor, editable)); return editable; } void glade_db_model_write_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlContext * context, GladeXmlNode * node) { GtkTreeIter iter; GtkTreeModel * m; GladeDbList * l; GladeProperty * prop; if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET)) return; prop = glade_widget_get_property (widget, "use-file"); glade_property_write (prop, context, node); prop = glade_widget_get_property (widget, "sql"); glade_property_write (prop, context, node); GWA_GET_CLASS (G_TYPE_OBJECT)->write_widget (adaptor, widget, context, node); //FIXME prop = glade_widget_get_property (widget, "links"); // Custom tag for the "links" property, e.g.: // // // if ((l = g_value_get_boxed (glade_property_inline_value (prop)))) { m = GTK_TREE_MODEL (l->list); if (gtk_tree_model_get_iter_first (m, &iter)) { GladeXmlNode * links_node = glade_xml_node_new (context, "links"); do { gchar * field; GladeWidget * param; gboolean linked; GladeXmlNode * link_node; gtk_tree_model_get (m, &iter ,LINKS_FIELD_COL, &field ,LINKS_PARAM_COL, ¶m ,LINKS_LINKED_COL, &linked , -1); link_node = glade_xml_node_new (context, "link"); glade_xml_node_append_child (links_node, link_node); glade_xml_node_set_property_string (link_node, "field", field ? field : ""); glade_xml_node_set_property_string (link_node, "param", param ? glade_widget_get_name (param) : ""); glade_xml_node_set_property_boolean (link_node, "linked", linked); g_free (field); } while (gtk_tree_model_iter_next (m, &iter)); if (!glade_xml_node_get_children (links_node)) glade_xml_node_delete (links_node); else glade_xml_node_append_child (node, links_node); } } prop = glade_widget_get_property (widget, "batch"); // Custom tag for the "links" property, e.g.: // // // if ((l = g_value_get_boxed (glade_property_inline_value (prop)))) { m = GTK_TREE_MODEL (l->list); if (gtk_tree_model_get_iter_first (m, &iter)) { GladeXmlNode * batch_node = glade_xml_node_new (context, "batch"); do { gchar * id; GladeWidget * param; GladeXmlNode * holder_node; gtk_tree_model_get (m, &iter ,BATCH_ID_COL, &id ,BATCH_PARAM_COL, ¶m , -1); holder_node = glade_xml_node_new (context, "holder"); glade_xml_node_append_child (batch_node, holder_node); glade_xml_node_set_property_string (holder_node, "id", id ? id : ""); glade_xml_node_set_property_string (holder_node, "param", param ? glade_widget_get_name (param) : ""); g_free (id); } while (gtk_tree_model_iter_next (m, &iter)); if (!glade_xml_node_get_children (batch_node)) glade_xml_node_delete (batch_node); else glade_xml_node_append_child (node, batch_node); } } } typedef struct { GtkListStore * store; GtkTreeIter * iter; gchar * param_name; } ParseData; void glade_db_model_on_parse_finished (GladeProject * p, ParseData * pd) { GladeWidget * param = glade_project_get_widget_by_name (p, pd->param_name); gint col = 1;// XXX LINKS_PARAM_COL and BATCH_PARAM_COL gtk_list_store_set (pd->store, pd->iter, col, param, -1); g_object_unref (pd->store); gtk_tree_iter_free (pd->iter); g_free (pd->param_name); g_free (pd); } void glade_db_model_read_widget (GladeWidgetAdaptor * adaptor, GladeWidget * widget, GladeXmlNode * node) { GladeXmlNode * prop_node; GladeProperty * prop; GladeProject * proj; GladeDbList * list; GtkListStore * store; if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET)) return; GWA_GET_CLASS (G_TYPE_OBJECT)->read_widget (adaptor, widget, node); if ((prop_node = glade_xml_search_child (node, "links"))) { GladeXmlNode * links_node = prop_node; proj = glade_widget_get_project (widget); list = g_new (GladeDbList, 1); store = gtk_list_store_new (LINKS_N_COLS, G_TYPE_STRING, GLADE_TYPE_WIDGET, G_TYPE_BOOLEAN); list->list = store; for (links_node = glade_xml_node_get_children (links_node); links_node; links_node = glade_xml_node_next (links_node)) { GtkTreeIter iter; gint col = LINKS_PARAM_COL; gchar * field = glade_xml_get_property_string (links_node, "field"), * param_name = glade_xml_get_property_string (links_node, "param"); gboolean linked = glade_xml_get_property_boolean (links_node, "linked", TRUE); GladeWidget * param = glade_project_get_widget_by_name (proj, param_name); gtk_list_store_append (store, &iter); if (!param) { // If the parameter hasn't been read yet, load it after the parse ParseData * pd; pd = g_new (ParseData, 1); pd->store = g_object_ref (store); pd->iter = gtk_tree_iter_copy (&iter); pd->param_name = g_strdup (param_name); g_signal_connect (proj, "parse-finished", G_CALLBACK (glade_db_model_on_parse_finished), pd); col = -1; } gtk_list_store_set (store, &iter ,LINKS_FIELD_COL, field ,LINKS_LINKED_COL, linked ,col, param ,-1); g_free (field); g_free (param_name); } prop = glade_widget_get_property (widget, "links"); glade_property_set (prop, list); } if ((prop_node = glade_xml_search_child (node, "batch"))) { GladeXmlNode * batch_node = prop_node; proj = glade_widget_get_project (widget); list = g_new (GladeDbList, 1); store = gtk_list_store_new (BATCH_N_COLS, G_TYPE_STRING, GLADE_TYPE_WIDGET); list->list = store; for (batch_node = glade_xml_node_get_children (batch_node); batch_node; batch_node = glade_xml_node_next (batch_node)) { GtkTreeIter iter; gint col = BATCH_PARAM_COL; gchar * id = glade_xml_get_property_string (batch_node, "id"), * param_name = glade_xml_get_property_string (batch_node, "param"); GladeWidget * param = glade_project_get_widget_by_name (proj, param_name); gtk_list_store_append (store, &iter); if (!param) { // If the parameter hasn't been read yet, load it after the parse ParseData * pd; pd = g_new (ParseData, 1); pd->store = g_object_ref (store); pd->iter = gtk_tree_iter_copy (&iter); pd->param_name = g_strdup (param_name); g_signal_connect (proj, "parse-finished", G_CALLBACK (glade_db_model_on_parse_finished), pd); col = -1; } gtk_list_store_set (store, &iter ,BATCH_ID_COL, id ,col, param ,-1); g_free (id); g_free (param_name); } prop = glade_widget_get_property (widget, "batch"); glade_property_set (prop, list); } }