This repository has been archived on 2024-07-15. You can view files and clone it, but cannot push or open issues or pull requests.
hedera/vn/vn-handler.c

568 lines
15 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}