/* * Copyright (C) 2012 - 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 "vn-handler.h" #define ACTION_GROUP_NAME "handler" G_DEFINE_TYPE (VnHandler, vn_handler, GTK_TYPE_BIN); /** * vn_handler_new: * * Creates a new handler * * Return value: #GtkWidget created. **/ GtkWidget * vn_handler_new () { return g_object_new (VN_TYPE_HANDLER, NULL); } /** * vn_handler_new_with_form: * @form: #DbIterator where the handler will be created * * Creates a new handler into a iterator gived * * Return value: #GtkWidget created. **/ GtkWidget * vn_handler_new_with_iterator (DbIterator * iterator) { return g_object_new (VN_TYPE_HANDLER, "iterator", iterator, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private static gboolean vn_handler_dialog (VnHandler * obj, gchar * message) { GtkWidget * toplevel = gtk_widget_get_toplevel (GTK_WIDGET (obj)), * dialog = gtk_message_dialog_new (GTK_WINDOW (toplevel) ,GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT ,GTK_MESSAGE_QUESTION ,GTK_BUTTONS_OK_CANCEL ,"%s" ,message ); gint response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return response == GTK_RESPONSE_OK; } static void vn_handler_on_add_activated (GSimpleAction * a, GVariant * p, gpointer obj) { db_iterator_insert (VN_HANDLER (obj)->iterator); } static void vn_handler_on_remove_activated (GSimpleAction * a, GVariant * p, gpointer obj) { if (db_iterator_get_mode (VN_HANDLER (obj)->iterator) == DB_ITERATOR_MODE_ON_DEMAND || vn_handler_dialog (obj, _("Are you sure you want to delete the current selection?"))) db_iterator_delete (VN_HANDLER (obj)->iterator); } static void vn_handler_on_save_activated (GSimpleAction * a, GVariant * p, gpointer obj) { if (db_iterator_get_mode (VN_HANDLER (obj)->iterator) != DB_ITERATOR_MODE_ON_DEMAND) db_iterator_perform_operations (VN_HANDLER (obj)->iterator); else if (vn_handler_dialog (obj, _("Are you sure you want to save the changes?"))) db_iterator_perform_operations (VN_HANDLER (obj)->iterator); } static void vn_handler_on_undo_activated (GSimpleAction * a, GVariant * p, gpointer obj) { if (vn_handler_dialog (obj, _("Are you sure you want to undo all changes?"))) db_iterator_reverse_operations (VN_HANDLER (obj)->iterator); } static void vn_handler_on_refresh_activated (GSimpleAction * a, GVariant * p, gpointer obj) { db_iterator_refresh (VN_HANDLER (obj)->iterator); } static void vn_handler_on_move_activated (GSimpleAction * action, GVariant * p, gpointer o) { VnHandler * obj = o; DbIteratorMove move; if (action == obj->move_previous) move = DB_ITERATOR_MOVE_PREVIOUS; else if (action == obj->move_next) move = DB_ITERATOR_MOVE_NEXT; else if (action == obj->move_last) move = DB_ITERATOR_MOVE_LAST; else move = DB_ITERATOR_MOVE_FIRST; db_iterator_move_to (obj->iterator, move); } static void vn_handler_refresh_save_undo_status (VnHandler * obj) { gboolean enabled = obj->iterator && db_iterator_has_pending_operations (obj->iterator); if (obj->show_flags & VN_HANDLER_SHOW_SAVE) g_simple_action_set_enabled (obj->save, enabled); if (obj->show_flags & VN_HANDLER_SHOW_UNDO) g_simple_action_set_enabled (obj->undo, enabled); } static void vn_handler_refresh_scroll_status (VnHandler * obj) { if (obj->show_flags & VN_HANDLER_SHOW_SCROLL) { gboolean enabled; gint row = db_iterator_get_row (obj->iterator); enabled = row > 0; g_simple_action_set_enabled (obj->move_first, enabled); g_simple_action_set_enabled (obj->move_previous, enabled); enabled = row != -1 && row < db_iterator_get_nrows (obj->iterator) - 1; g_simple_action_set_enabled (obj->move_next, enabled); g_simple_action_set_enabled (obj->move_last, enabled); } } static void vn_handler_on_data_changed (DbIterator * iterator, VnHandler * obj) { if (obj->show_flags & VN_HANDLER_SHOW_ADD) { gboolean enabled = db_iterator_get_update_flags (iterator) & DB_MODEL_INSERT && (db_iterator_get_nrows (iterator) < 1 || !obj->simple_record); g_simple_action_set_enabled (obj->add, enabled); } vn_handler_refresh_save_undo_status (obj); vn_handler_refresh_scroll_status (obj); } static void vn_handler_on_row_num_changed (DbIterator * iterator, VnHandler * obj) { if (obj->show_flags & VN_HANDLER_SHOW_REMOVE) { gboolean enabled = db_iterator_get_update_flags (iterator) & DB_MODEL_DELETE && db_iterator_get_nrows (iterator) > 0; g_simple_action_set_enabled (obj->remove, enabled); } vn_handler_refresh_scroll_status (obj); } static void vn_handler_on_operations_done (DbIterator * iterator, VnHandler * obj) { vn_handler_refresh_save_undo_status (obj); } static void action_group_set_enabled (GActionGroup * group, gboolean enabled) { gint i; gchar ** actions = g_action_group_list_actions (group); for (i = 0; actions[i]; i++) { GAction * a = g_action_map_lookup_action (G_ACTION_MAP (group), actions[i]); g_simple_action_set_enabled (G_SIMPLE_ACTION (a), enabled); } } static void vn_handler_on_status_changed (DbIterator * iterator, gboolean ready, VnHandler * obj) { action_group_set_enabled (obj->group, ready); vn_handler_on_row_num_changed (iterator, obj); vn_handler_on_data_changed (iterator, obj); } static void vn_handler_refresh_status (VnHandler * obj) { if (!obj->iterator) action_group_set_enabled (obj->group, FALSE); else vn_handler_on_status_changed (obj->iterator, db_iterator_is_ready (obj->iterator), obj); } static struct { gchar * icon; gchar * tooltip; } actions_data[] = { { "edit-undo-symbolic" ,N_("Undo changes") },{ "document-save-symbolic" ,N_("Save changes") },{ "view-refresh-symbolic" ,N_("Refresh data") },{ "list-remove-symbolic" ,N_("Remove record") },{ "list-add-symbolic" ,N_("Add record") },{ "go-first-symbolic" ,N_("Move to the first row") },{ "go-previous-symbolic" ,N_("Move to the previous row") },{ "go-next-symbolic" ,N_("Move to the next row") },{ "go-last-symbolic" ,N_("Move to the last row") } }; static VnHandlerShowFlags entries_flags[] = { VN_HANDLER_SHOW_UNDO ,VN_HANDLER_SHOW_SAVE ,VN_HANDLER_SHOW_REFRESH ,VN_HANDLER_SHOW_REMOVE ,VN_HANDLER_SHOW_ADD ,VN_HANDLER_SHOW_SCROLL ,VN_HANDLER_SHOW_SCROLL ,VN_HANDLER_SHOW_SCROLL ,VN_HANDLER_SHOW_SCROLL }; static GActionEntry entries[] = { { "undo" ,vn_handler_on_undo_activated },{ "save" ,vn_handler_on_save_activated },{ "refresh" ,vn_handler_on_refresh_activated },{ "remove" ,vn_handler_on_remove_activated },{ "add" ,vn_handler_on_add_activated },{ "move-first" ,vn_handler_on_move_activated },{ "move-previous" ,vn_handler_on_move_activated },{ "move-next" ,vn_handler_on_move_activated },{ "move-last" ,vn_handler_on_move_activated } }; static guint n_entries = G_N_ELEMENTS (entries); //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * vn_handler_set_show_flags: * @obj: a #VnHandler * @show_flags: the buttons to be shown * * Sets the buttons that will be shown on the interface. **/ void vn_handler_set_show_flags (VnHandler * obj, VnHandlerShowFlags show_flags) { gint i; GList * list = gtk_container_get_children (GTK_CONTAINER (obj->buttons)), * l = list; obj->show_flags = show_flags; for (i = 0; i < n_entries && l; i++) { GtkWidget * button = l->data; if (obj->show_flags & entries_flags[i]) gtk_widget_show (button); else gtk_widget_hide (button); l = l->next; } if (obj->show_flags & VN_HANDLER_SHOW_ADD) obj->add = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "add")); if (obj->show_flags & VN_HANDLER_SHOW_REMOVE) obj->remove = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "remove")); if (obj->show_flags & VN_HANDLER_SHOW_SAVE) obj->save = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "save")); if (obj->show_flags & VN_HANDLER_SHOW_UNDO) obj->undo = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "undo")); if (obj->show_flags & VN_HANDLER_SHOW_SCROLL) { obj->move_first = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "move-first")); obj->move_previous = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "move-previous")); obj->move_next = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "move-next")); obj->move_last = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (obj->group), "move-last")); } vn_handler_refresh_status (obj); } /** * vn_handler_get_iterator: * @obj: a #VnHandler * * Gets the iterator handled by #VnHandler * * Return value: (transfer none) (allow-none): the #DbIterator **/ DbIterator * vn_handler_get_iterator (VnHandler * obj) { return obj->iterator; } /** * vn_handler_set_iterator: * @obj: a #VnHandler * @iterator: the iterator to be handled * * Sets the iterator handled by #VnHandler **/ void vn_handler_set_iterator (VnHandler * obj, DbIterator * iterator) { g_return_if_fail (VN_IS_HANDLER (obj)); g_return_if_fail (DB_IS_ITERATOR (iterator) || !iterator); if (obj->iterator) { g_object_disconnect (obj->iterator ,"any-signal", vn_handler_on_status_changed, obj ,"any-signal", vn_handler_on_data_changed, obj ,"any-signal", vn_handler_on_row_num_changed, obj ,"any-signal", vn_handler_on_operations_done, obj ,NULL ); g_clear_object (&obj->iterator); } if (iterator) { obj->iterator = g_object_ref (iterator); g_object_connect (iterator ,"signal::status-changed", vn_handler_on_status_changed, obj ,"signal::data-changed", vn_handler_on_data_changed, obj ,"signal::row-num-changed", vn_handler_on_row_num_changed, obj ,"signal::operations-done", vn_handler_on_operations_done, obj ,NULL ); } vn_handler_refresh_status (obj); } /** * vn_handler_set_simple_record: * @obj: a #VnHandler * @simple: %FALSE if model allows multiple records, %TRUE otherwise * * Sets if it is used to handle a iterator with a single record. **/ void vn_handler_set_simple_record (VnHandler * obj, gboolean simple) { g_return_if_fail (VN_IS_HANDLER (obj)); obj->simple_record = simple; } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties enum { PROP_FORM = 1 ,PROP_SHOW_FLAGS ,PROP_SIMPLE_RECORD }; static void vn_handler_set_property (VnHandler * obj, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_FORM: vn_handler_set_iterator (obj, g_value_get_object (value)); break; case PROP_SHOW_FLAGS: vn_handler_set_show_flags (obj, g_value_get_flags (value)); break; case PROP_SIMPLE_RECORD: vn_handler_set_simple_record (obj, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } static void vn_handler_get_property (VnHandler * obj, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_FORM: g_value_set_object (value, obj->iterator); break; case PROP_SHOW_FLAGS: g_value_set_flags (value, obj->show_flags); break; case PROP_SIMPLE_RECORD: g_value_set_boolean (value, obj->simple_record); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class static void vn_handler_init (VnHandler * obj) { gint i; gchar * css; GtkStyleContext * context; GtkCssProvider * provider; obj->add = NULL; obj->remove = NULL; obj->move_first = NULL; obj->move_previous = NULL; obj->move_next = NULL; obj->move_last = NULL; obj->iterator = NULL; obj->group = G_ACTION_GROUP (g_simple_action_group_new ()); g_action_map_add_action_entries (G_ACTION_MAP (obj->group), entries, n_entries, obj); gtk_widget_insert_action_group (GTK_WIDGET (obj), ACTION_GROUP_NAME, obj->group); obj->buttons = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON_BOX ,"layout-style", GTK_BUTTONBOX_EXPAND ,"homogeneous", FALSE ,"halign", GTK_ALIGN_END ,NULL )); context = gtk_widget_get_style_context (obj->buttons); provider = gtk_css_provider_get_default (); css = "VnHandler GtkButtonBox\n" "{\n" " -GtkButtonBox-child-min-width: 0;\n" " -GtkButtonBox-child-internal-pad-x: 0;\n" "}"; if (gtk_css_provider_load_from_data (provider, css, -1, NULL)) gtk_style_context_add_provider (context, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); else g_object_unref (provider); gtk_container_add (GTK_CONTAINER (obj), obj->buttons); for (i = 0; i < n_entries; i++) { GtkWidget * button = gtk_button_new_from_icon_name (actions_data[i].icon, GTK_ICON_SIZE_BUTTON); gchar * action_name = g_strconcat (ACTION_GROUP_NAME, ".", entries[i].name, NULL); gtk_actionable_set_action_name (GTK_ACTIONABLE (button), action_name); g_free (action_name); gtk_widget_set_tooltip_text (button, actions_data[i].tooltip); gtk_widget_set_no_show_all (button, TRUE); gtk_box_pack_start (GTK_BOX (obj->buttons), button, FALSE, FALSE, 0); } } static void vn_handler_finalize (VnHandler * obj) { vn_handler_set_iterator (obj, NULL); G_OBJECT_CLASS (vn_handler_parent_class)->finalize (G_OBJECT (obj)); } static void vn_handler_class_init (VnHandlerClass * klass) { GObjectClass * k = G_OBJECT_CLASS (klass); k->finalize = (GObjectFinalizeFunc) vn_handler_finalize; k->set_property = (GObjectSetPropertyFunc) vn_handler_set_property; k->get_property = (GObjectGetPropertyFunc) vn_handler_get_property; g_object_class_install_property (k, PROP_FORM, g_param_spec_object ("iterator" ,"Iterator" ,"The handled iterator" ,DB_TYPE_ITERATOR ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_SHOW_FLAGS, g_param_spec_flags ("show-flags" ,_("Show flags") ,_("Sets the buttons that will be shown on the interface") ,VN_TYPE_HANDLER_SHOW_FLAGS ,VN_HANDLER_SHOW_UNDO | VN_HANDLER_SHOW_SAVE | VN_HANDLER_SHOW_REMOVE | VN_HANDLER_SHOW_ADD ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); g_object_class_install_property (k, PROP_SIMPLE_RECORD, g_param_spec_boolean ("simple-record" ,_("Simple record") ,_("Sets if it is used to handle a iterator with a single record") ,FALSE ,G_PARAM_CONSTRUCT | G_PARAM_READWRITE )); } GType vn_handler_show_flags_get_type () { static GType type = 0; if (type == 0) { static const GFlagsValue values[] = { {VN_HANDLER_SHOW_REFRESH, "VN_HANDLER_SHOW_REFRESH", "refresh"} ,{VN_HANDLER_SHOW_UNDO, "VN_HANDLER_SHOW_UNDO", "undo"} ,{VN_HANDLER_SHOW_SAVE, "VN_HANDLER_SHOW_SAVE", "save"} ,{VN_HANDLER_SHOW_REMOVE, "VN_HANDLER_SHOW_REMOVE", "remove"} ,{VN_HANDLER_SHOW_ADD, "VN_HANDLER_SHOW_ADD", "add"} ,{VN_HANDLER_SHOW_SCROLL, "VN_HANDLER_SHOW_SCROLL", "scroll"} ,{0, NULL, NULL} }; type = g_flags_register_static (g_intern_static_string ("VnHandlerShowFlags"), values); } return type; }