568 lines
15 KiB
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;
|
|
} |