1544 lines
37 KiB
C
1544 lines
37 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-gui.h"
|
|
#include <gdome.h>
|
|
#include <stdlib.h>
|
|
#include <glib/gstdio.h>
|
|
|
|
#include <libxml/tree.h>
|
|
#include <libxml/parser.h>
|
|
#include <libxml/valid.h>
|
|
|
|
#define MAIN_UI _GUI_DIR"/main.glade"
|
|
#define CHILD_WINDOW_UI _GUI_DIR"/child-window.glade"
|
|
#define ACTIONS_UI _GUI_DIR"/actions.glade"
|
|
#define MENUBAR_XML _GUI_DIR"/menubar.ui"
|
|
#define MODULE_DTD _DTD_DIR"/module.dtd"
|
|
|
|
#define S(string) (gdome_str_mkref (string))
|
|
#define gtk_builder_get(builder, id) ((gpointer) gtk_builder_get_object (builder, id))
|
|
|
|
/**
|
|
* SECTION: vn-gui
|
|
* @Short_description: GUI manager
|
|
* @Title: VnGui
|
|
*
|
|
* Manages most of the GUI operations.
|
|
**/
|
|
G_DEFINE_TYPE (VnGui, vn_gui, G_TYPE_OBJECT);
|
|
|
|
struct _VnWindow
|
|
{
|
|
VnGui * obj;
|
|
GtkWindow * widget;
|
|
GtkNotebook * notebook;
|
|
GtkUIManager * manager;
|
|
GtkWidget * toolbar;
|
|
VnForm * active_form;
|
|
GtkToggleAction * dynamic_tabs;
|
|
GtkToggleAction * view_toolbar;
|
|
guint merge_id;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
VnGui * gui;
|
|
gchar * name;
|
|
}
|
|
FormData;
|
|
|
|
typedef struct
|
|
{
|
|
GtkActionEntry * entry;
|
|
FormData * form;
|
|
}
|
|
ActionData;
|
|
|
|
typedef struct
|
|
{
|
|
GSList * action_data;
|
|
VnMod * mod;
|
|
}
|
|
ModData;
|
|
|
|
enum {
|
|
COL_ICON
|
|
,COL_NAME
|
|
,COL_TITLE
|
|
,COL_TYPE
|
|
,COL_MODULE
|
|
,COL_COUNT
|
|
};
|
|
|
|
enum {
|
|
LOGOUT
|
|
,EXIT
|
|
,LAST_SIGNAL
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
VnGui * obj;
|
|
gboolean aux;
|
|
GError * error;
|
|
GThread * thread;
|
|
}
|
|
GuiData;
|
|
|
|
static void vn_gui_reconnect (VnGui * obj);
|
|
static void vn_gui_on_conn_error (DbConn * conn, const GError * error, VnGui * obj);
|
|
static void vn_gui_on_conn_status_changed (DbConn * conn, DbConnStatus status, VnGui * obj);
|
|
void vn_gui_on_open_form_activated (GtkAction * action, FormData * form_data);
|
|
void vn_gui_on_child_destroyed (GtkWindow * widget, VnWindow * window);
|
|
void vn_gui_on_page_removed (GtkNotebook * notebook, GtkWidget * page, guint num, VnWindow * window);
|
|
void vn_gui_on_main_page_removed (GtkNotebook * notebook, GtkWidget * page, guint num, VnWindow * window);
|
|
|
|
static guint signals[LAST_SIGNAL] = {0};
|
|
|
|
/**
|
|
* vn_gui_new:
|
|
* @app: a #GtkApplication
|
|
* @conn: the #VnLogin
|
|
*
|
|
* Creates a new Gui object.
|
|
*
|
|
* Return value: the created #VnGui
|
|
**/
|
|
VnGui * vn_gui_new (GtkApplication * app, DbConn * conn)
|
|
{
|
|
return g_object_new (VN_TYPE_GUI, "app", app, "conn", conn, NULL);
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Private
|
|
|
|
static void vn_gui_free_action_data (ActionData * data)
|
|
{
|
|
if (data)
|
|
{
|
|
if (data->form)
|
|
g_free (data->form->name);
|
|
|
|
g_free (data->form);
|
|
|
|
if (data->entry)
|
|
{
|
|
g_free ((gchar *) data->entry->name);
|
|
g_free ((gchar *) data->entry->stock_id);
|
|
g_free ((gchar *) data->entry->label);
|
|
g_free ((gchar *) data->entry->accelerator);
|
|
g_free ((gchar *) data->entry->tooltip);
|
|
}
|
|
|
|
g_free (data->entry);
|
|
}
|
|
|
|
g_free (data);
|
|
}
|
|
|
|
static void vn_gui_free_mod_data (ModData * data)
|
|
{
|
|
if (data->action_data)
|
|
g_slist_free_full (data->action_data,
|
|
(GDestroyNotify) vn_gui_free_action_data);
|
|
}
|
|
|
|
/*
|
|
* Frees the #GuiData struct.
|
|
*/
|
|
static void gui_data_free (GuiData * gui_data)
|
|
{
|
|
if (gui_data->error)
|
|
g_error_free (gui_data->error);
|
|
|
|
g_object_unref (gui_data->obj);
|
|
g_thread_unref (gui_data->thread);
|
|
g_free (gui_data);
|
|
}
|
|
|
|
static void vn_gui_free_window (VnGui * obj, VnWindow * window)
|
|
{
|
|
g_signal_handlers_disconnect_by_func (window->widget,
|
|
vn_gui_on_child_destroyed, window);
|
|
g_signal_handlers_disconnect_by_func (window->notebook,
|
|
vn_gui_on_page_removed, window);
|
|
g_signal_handlers_disconnect_by_func (window->notebook,
|
|
vn_gui_on_main_page_removed, window);
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (window->widget));
|
|
g_object_unref (window->manager);
|
|
g_free (window);
|
|
}
|
|
|
|
static VnWindow * vn_gui_get_active_window (VnGui * obj)
|
|
{
|
|
GSList * n;
|
|
|
|
for (n = obj->windows; n; n = n->next)
|
|
if (gtk_window_is_active (((VnWindow *) n->data)->widget))
|
|
return n->data;
|
|
|
|
return obj->main_window;
|
|
}
|
|
|
|
/*
|
|
* Loads a module and all of its forms.
|
|
*/
|
|
static void vn_gui_load_module (VnGui * obj, const gchar * dir, const gchar * file)
|
|
{
|
|
gint n;
|
|
gchar * path;
|
|
gchar * mod_title_strip, * mod_name;
|
|
GModule * module = NULL;
|
|
VnMod * mod = NULL;
|
|
GdomeException e;
|
|
GdomeDocument * doc;
|
|
GdomeDOMImplementation * di;
|
|
GdomeNodeList * nl, * action_nl;
|
|
GdomeElement * el;
|
|
GdomeNode * node;
|
|
GdomeDOMString * mod_title;
|
|
GdomeDOMString * library;
|
|
|
|
// Validating the module definition against the DTD (using libxml2 directly)
|
|
|
|
xmlValidCtxtPtr ctxt = xmlNewValidCtxt ();
|
|
|
|
path = g_strdup_printf ("%s/%s", dir, file);
|
|
|
|
if (ctxt)
|
|
{
|
|
gboolean valid = FALSE;
|
|
xmlDocPtr doc = xmlParseFile (path);
|
|
|
|
if (doc)
|
|
{
|
|
xmlDtdPtr dtd = xmlParseDTD (NULL, (const xmlChar *) MODULE_DTD);
|
|
|
|
if (dtd)
|
|
valid = xmlValidateDtd (ctxt, doc, dtd);
|
|
else
|
|
g_warning ("The DTD is not well formed");
|
|
|
|
xmlFreeDtd (dtd);
|
|
}
|
|
|
|
xmlFreeValidCtxt (ctxt);
|
|
xmlFreeDoc (doc);
|
|
|
|
if (!valid)
|
|
{
|
|
g_free (path);
|
|
g_warning ("The module definition at \"%s\" is not valid", file);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Getting the module info from XML file
|
|
|
|
di = gdome_di_mkref ();
|
|
doc = gdome_di_createDocFromURI (di, path, 0, &e);
|
|
|
|
g_free (path);
|
|
|
|
gdome_di_unref (di, &e);
|
|
|
|
if (doc)
|
|
{
|
|
nl = gdome_doc_getElementsByTagName (doc, S("library"), &e);
|
|
el = (GdomeElement *) gdome_nl_item (nl, 0, &e);
|
|
gdome_nl_unref (nl, &e);
|
|
|
|
library = gdome_el_getAttribute (el, S("name"), &e);
|
|
mod_name = g_strdup (library->str);
|
|
|
|
node = gdome_el_firstChild (el, &e);
|
|
mod_title = gdome_n_nodeValue (node, &e);
|
|
mod_title_strip = g_strstrip (g_strdup (mod_title->str));
|
|
|
|
nl = gdome_doc_getElementsByTagName (doc, S("form"), &e);
|
|
action_nl = gdome_doc_getElementsByTagName (doc, S("action"), &e);
|
|
|
|
gdome_str_unref (library);
|
|
gdome_doc_unref (doc, &e);
|
|
gdome_n_unref (node, &e);
|
|
gdome_el_unref (el, &e);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: Error loading module info file: %s", (gchar *) file);
|
|
return;
|
|
}
|
|
|
|
// Loading the module dynamically
|
|
|
|
for (n = 0; obj->lib_dirs[n] && !module; n++)
|
|
{
|
|
path = g_module_build_path (obj->lib_dirs[n], mod_name);
|
|
module = g_module_open (path, 0);
|
|
g_free (path);
|
|
}
|
|
|
|
if (module)
|
|
{
|
|
g_module_make_resident (module);
|
|
mod = g_object_new (VN_TYPE_MOD
|
|
,"name" ,mod_name
|
|
,"data-dir" ,dir
|
|
,"module" ,module
|
|
,NULL
|
|
);
|
|
}
|
|
else
|
|
g_warning ("VnGui: Can't load module %s: %s"
|
|
,mod_name
|
|
,g_module_error ()
|
|
);
|
|
|
|
// If successful, load forms, actions and UI
|
|
|
|
if (mod)
|
|
{
|
|
GType type;
|
|
gulong len, n;
|
|
gchar * c_name;
|
|
gchar * title_strip;
|
|
gchar * ui_file;
|
|
gchar * buffer;
|
|
GdomeDOMString * name;
|
|
GdomeDOMString * icon;
|
|
GdomeDOMString * action_name;
|
|
GdomeDOMString * accel;
|
|
GdomeDOMString * title;
|
|
gchar * symbol_name;
|
|
const gchar * text_dom;
|
|
GtkTreeIter parent_iter;
|
|
GtkTreeIter * iter;
|
|
VnFormGetTypeFunc mod_get_type_func;
|
|
GError * err = NULL;
|
|
GSList * mod_actions = NULL;
|
|
ActionData * action_data;
|
|
GtkActionGroup * actions = gtk_action_group_new (mod_name);
|
|
|
|
// Creating folder to put forms inside
|
|
|
|
text_dom = vn_mod_get_text_domain (mod);
|
|
gtk_tree_store_append (obj->tree, &parent_iter, NULL);
|
|
gtk_tree_store_set (obj->tree, &parent_iter
|
|
,COL_ICON ,"gtk-directory"
|
|
,COL_TITLE ,g_dgettext (text_dom, mod_title_strip)
|
|
,COL_TYPE ,G_TYPE_NONE
|
|
,COL_NAME ,NULL
|
|
,-1
|
|
);
|
|
|
|
len = gdome_nl_length (nl, &e);
|
|
|
|
for (n = 0; n < len; n++)
|
|
{
|
|
// Getting form info
|
|
|
|
el = (GdomeElement *) gdome_nl_item (nl, n, &e);
|
|
icon = gdome_el_getAttribute (el, S("icon"), &e);
|
|
action_name = gdome_el_getAttribute (el, S("action-name"), &e);
|
|
accel = gdome_el_getAttribute (el, S("accel"), &e);
|
|
|
|
name = gdome_el_getAttribute (el, S("name"), &e);
|
|
c_name = g_strdelimit (g_strdup (name->str), "-. ", '_');
|
|
|
|
node = gdome_el_firstChild (el, &e);
|
|
title = gdome_n_nodeValue (node, &e);
|
|
title_strip = g_strstrip (g_strdup (title->str));
|
|
|
|
gdome_n_unref (node, &e);
|
|
gdome_el_unref (el, &e);
|
|
|
|
// Loading form
|
|
|
|
symbol_name = g_strdup_printf ("vn_%s_get_type", c_name);
|
|
|
|
if (g_module_symbol (module, symbol_name, (gpointer) &mod_get_type_func))
|
|
{
|
|
type = mod_get_type_func ();
|
|
|
|
if (g_type_is_a (type, VN_TYPE_FORM))
|
|
{
|
|
iter = g_new (GtkTreeIter, 1);
|
|
gtk_tree_store_append (obj->tree, iter, &parent_iter);
|
|
gtk_tree_store_set (obj->tree, iter
|
|
,COL_NAME ,name->str
|
|
,COL_ICON ,icon->str
|
|
,COL_TITLE ,g_dgettext (text_dom, title_strip)
|
|
,COL_TYPE ,type
|
|
,COL_MODULE ,mod
|
|
,-1
|
|
);
|
|
g_hash_table_replace (obj->forms, g_strdup (name->str), iter);
|
|
|
|
if (g_strcmp0 ("", action_name->str))
|
|
{
|
|
action_data = g_new (ActionData, 1);
|
|
action_data->entry = g_new (GtkActionEntry, 1);
|
|
action_data->entry->name = g_strdup (action_name->str);
|
|
action_data->entry->stock_id = g_strdup (icon->str);
|
|
action_data->entry->label = g_strdup (title_strip);
|
|
action_data->entry->accelerator = g_strdup (accel->str);
|
|
action_data->entry->tooltip = NULL;
|
|
action_data->entry->callback =
|
|
(GCallback) vn_gui_on_open_form_activated;
|
|
|
|
action_data->form = g_new (FormData, 1);
|
|
action_data->form->name = g_strdup (name->str);
|
|
action_data->form->gui = obj;
|
|
|
|
mod_actions = g_slist_prepend (mod_actions, action_data);
|
|
|
|
gtk_action_group_add_actions (actions
|
|
,action_data->entry, 1
|
|
,action_data->form
|
|
);
|
|
}
|
|
}
|
|
else
|
|
g_warning ("VnGui: %s isn't a VnForm", g_type_name (type));
|
|
}
|
|
else
|
|
g_warning ("VnGui: Error loading form: %s", g_module_error ());
|
|
|
|
g_free (c_name);
|
|
gdome_str_unref (name);
|
|
gdome_str_unref (icon);
|
|
gdome_str_unref (action_name);
|
|
gdome_str_unref (accel);
|
|
gdome_str_unref (title);
|
|
g_free (title_strip);
|
|
g_free (symbol_name);
|
|
}
|
|
|
|
len = gdome_nl_length (action_nl, &e);
|
|
|
|
for (n = 0; n < len; n++)
|
|
{
|
|
el = (GdomeElement *) gdome_nl_item (action_nl, n, &e);
|
|
name = gdome_el_getAttribute (el, S("name"), &e);
|
|
|
|
node = gdome_el_firstChild (el, &e);
|
|
title = gdome_n_nodeValue (node, &e);
|
|
title_strip = g_strstrip (g_strdup (title->str));
|
|
|
|
gdome_el_unref (el, &e);
|
|
gdome_n_unref (node, &e);
|
|
gdome_str_unref (title);
|
|
|
|
action_data = g_new (ActionData, 1);
|
|
action_data->entry = g_new0 (GtkActionEntry, 1);
|
|
action_data->entry->name = g_strdup (name->str);
|
|
action_data->entry->label = g_strdup (title_strip);
|
|
action_data->form = NULL;
|
|
|
|
mod_actions = g_slist_prepend (mod_actions, action_data);
|
|
|
|
gtk_action_group_add_actions (actions, action_data->entry, 1, NULL);
|
|
|
|
gdome_str_unref (name);
|
|
g_free (title_strip);
|
|
}
|
|
|
|
ui_file = g_strdup_printf ("%s/%s.ui", dir, mod_name);
|
|
|
|
if (g_file_get_contents (ui_file, &buffer, NULL, &err))
|
|
{
|
|
ModData * mod_data = g_new (ModData, 1);
|
|
mod_data->action_data = mod_actions;
|
|
mod_data->mod = mod;
|
|
|
|
vn_mod_set_ui (mod, buffer);
|
|
obj->modules = g_slist_prepend (obj->modules, mod_data);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
g_slist_free_full (mod_actions,
|
|
(GDestroyNotify) vn_gui_free_action_data);
|
|
}
|
|
|
|
g_free (ui_file);
|
|
// g_object_unref (mod);
|
|
g_object_unref (actions);
|
|
}
|
|
|
|
g_free (mod_title_strip);
|
|
g_free (mod_name);
|
|
gdome_str_unref (mod_title);
|
|
gdome_nl_unref (nl, &e);
|
|
gdome_nl_unref (action_nl, &e);
|
|
}
|
|
|
|
static VnWindow * vn_gui_add_window (VnGui * obj, GtkWindow * widget, GtkNotebook * notebook)
|
|
{
|
|
GdkRGBA color;
|
|
GSList * n, * m;
|
|
GError * err = NULL;
|
|
GtkActionGroup * actions = NULL;
|
|
GtkStyleContext * style;
|
|
GtkBuilder * builder;
|
|
VnWindow * window;
|
|
|
|
window = g_new (VnWindow, 1);
|
|
window->obj = obj;
|
|
window->widget = widget;
|
|
window->notebook = notebook;
|
|
window->manager = gtk_ui_manager_new ();
|
|
window->active_form = NULL;
|
|
window->merge_id = 0;
|
|
|
|
obj->windows = g_slist_prepend (obj->windows, window);
|
|
gtk_application_add_window (obj->app, widget);
|
|
|
|
gtk_notebook_set_group_name (notebook,
|
|
g_application_get_application_id (G_APPLICATION (obj->app)));
|
|
|
|
style = gtk_widget_get_style_context (GTK_WIDGET (widget));
|
|
gtk_style_context_get_background_color (style,
|
|
GTK_STATE_FLAG_NORMAL, &color);
|
|
gtk_widget_override_background_color (GTK_WIDGET (notebook),
|
|
GTK_STATE_FLAG_NORMAL, &color);
|
|
|
|
gtk_widget_show_all (GTK_WIDGET (widget));
|
|
|
|
// Loading the bars and associated actions
|
|
|
|
builder = gtk_builder_new ();
|
|
|
|
if (gtk_builder_add_from_file (builder, ACTIONS_UI, &err))
|
|
{
|
|
actions = gtk_builder_get (builder, "main-actions");
|
|
gtk_builder_connect_signals (builder, window);
|
|
gtk_ui_manager_insert_action_group (window->manager, actions, -1);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_clear_error (&err);
|
|
}
|
|
|
|
if (gtk_ui_manager_add_ui_from_file (window->manager, MENUBAR_XML, &err))
|
|
{
|
|
GtkBox * box = GTK_BOX (gtk_bin_get_child (GTK_BIN (widget)));
|
|
GtkWidget * menubar = gtk_ui_manager_get_widget (window->manager, "/MenuBar");
|
|
GtkWidget * toolbar = gtk_ui_manager_get_widget (window->manager, "/Toolbar");
|
|
|
|
gtk_box_pack_start (box, menubar, FALSE, FALSE, 0);
|
|
gtk_box_pack_start (box, toolbar, FALSE, FALSE, 0);
|
|
gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
|
|
GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
|
|
gtk_window_add_accel_group (widget,
|
|
gtk_ui_manager_get_accel_group (window->manager));
|
|
|
|
window->toolbar = toolbar;
|
|
}
|
|
else
|
|
{
|
|
window->toolbar = NULL;
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
}
|
|
|
|
if (actions)
|
|
{
|
|
// TODO: Load from config file the default value for toggle actions.
|
|
|
|
window->dynamic_tabs = gtk_builder_get (builder, "menu-view-tabs");
|
|
gtk_toggle_action_set_active (window->dynamic_tabs, TRUE);
|
|
|
|
window->view_toolbar = gtk_builder_get (builder, "menu-view-toolbar");
|
|
gtk_toggle_action_set_active (window->view_toolbar, TRUE);
|
|
}
|
|
|
|
g_object_unref (builder);
|
|
|
|
// Loading the modules actions
|
|
|
|
for (n = obj->modules; n; n = n->next)
|
|
{
|
|
ModData * mod_data = n->data;
|
|
GtkActionGroup * mod_actions = gtk_action_group_new (vn_mod_get_name (mod_data->mod));
|
|
|
|
for (m = mod_data->action_data; m; m = m->next)
|
|
{
|
|
ActionData * action_data = m->data;
|
|
|
|
gtk_action_group_add_actions (mod_actions
|
|
,action_data->entry, 1
|
|
,action_data->form
|
|
);
|
|
}
|
|
|
|
gtk_ui_manager_insert_action_group (window->manager, mod_actions, -1);
|
|
g_object_unref (mod_actions);
|
|
|
|
if (!gtk_ui_manager_add_ui_from_string (window->manager,
|
|
vn_mod_get_ui (mod_data->mod), -1, &err))
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
}
|
|
}
|
|
|
|
gtk_ui_manager_ensure_update (window->manager);
|
|
return window;
|
|
}
|
|
|
|
/*
|
|
* Shows an error dialog.
|
|
*/
|
|
static void vn_gui_show_error (VnGui * obj, const GError * error)
|
|
{
|
|
GtkWidget * dialog;
|
|
GtkWindow * window = vn_gui_get_active_window (obj)->widget;
|
|
|
|
if (error && error->code == DB_CONN_ERROR_LOST)
|
|
dialog = gtk_message_dialog_new (window
|
|
,GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT
|
|
,GTK_MESSAGE_QUESTION
|
|
,GTK_BUTTONS_YES_NO
|
|
,_("Connection has been lost. Do you want to reconnect?")
|
|
);
|
|
else
|
|
dialog = gtk_message_dialog_new (window
|
|
,GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT
|
|
,GTK_MESSAGE_WARNING
|
|
,GTK_BUTTONS_CLOSE
|
|
,_("An error occurred in the connection.")
|
|
);
|
|
|
|
gtk_window_set_title (GTK_WINDOW (dialog), _("Database error"));
|
|
|
|
if (error)
|
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
|
|
"%s", error->message);
|
|
else
|
|
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
|
|
_("Unknown error"));
|
|
|
|
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
|
|
vn_gui_reconnect (obj);
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (dialog));
|
|
}
|
|
|
|
/*
|
|
* Closes and saves the GUI interface.
|
|
*/
|
|
static void vn_gui_close (VnGui * obj)
|
|
{
|
|
GSList * n;
|
|
|
|
g_return_if_fail (VN_IS_GUI (obj));
|
|
|
|
if (obj->main_window)
|
|
{
|
|
vn_gui_save (obj);
|
|
g_object_disconnect (obj->conn
|
|
,"any_signal", vn_gui_on_conn_error, obj
|
|
,"any_signal", vn_gui_on_conn_status_changed, obj
|
|
,NULL
|
|
);
|
|
|
|
for (n = obj->windows; n; n = n->next)
|
|
vn_gui_free_window (obj, n->data);
|
|
|
|
g_slist_free (obj->windows);
|
|
obj->windows = NULL;
|
|
obj->main_window = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Idle function that completes the reopen thread.
|
|
*/
|
|
static gboolean vn_gui_reconnect_idle (GuiData * gui_data)
|
|
{
|
|
if (!gui_data->aux)
|
|
vn_gui_show_error (gui_data->obj, gui_data->error);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Thread function that tryes to reopen the connection asynchronously.
|
|
*/
|
|
static void vn_gui_reconnect_thread (GuiData * gui_data)
|
|
{
|
|
gui_data->aux = db_conn_reconnect (gui_data->obj->conn, &gui_data->error);
|
|
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
|
(GSourceFunc) vn_gui_reconnect_idle, gui_data, (GDestroyNotify) gui_data_free);
|
|
}
|
|
|
|
/*
|
|
* Reconnects to database.
|
|
*/
|
|
void vn_gui_reconnect (VnGui * obj)
|
|
{
|
|
GuiData * gui_data = g_new (GuiData, 1);
|
|
gui_data->obj = g_object_ref (obj);
|
|
gui_data->aux = FALSE;
|
|
gui_data->error = NULL;
|
|
gui_data->thread = g_thread_new ("vn-gui-reconnect",
|
|
(GThreadFunc) vn_gui_reconnect_thread, gui_data);
|
|
}
|
|
|
|
/*
|
|
* Saves the login information and closes the main GUI.
|
|
*/
|
|
static gboolean vn_gui_logout_idle (GuiData * gui_data)
|
|
{
|
|
vn_gui_close (gui_data->obj);
|
|
|
|
if (gui_data->aux)
|
|
g_signal_emit (gui_data->obj, signals[EXIT], 0);
|
|
else
|
|
g_signal_emit (gui_data->obj, signals[LOGOUT], 0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Thread function that tryes to close the connection asynchronously.
|
|
*/
|
|
static void vn_gui_logout_thread (GuiData * gui_data)
|
|
{
|
|
db_conn_close (gui_data->obj->conn, TRUE);
|
|
g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
|
|
(GSourceFunc) vn_gui_logout_idle, gui_data, (GDestroyNotify) gui_data_free);
|
|
}
|
|
|
|
/*
|
|
* Closes the connection and the user interface.
|
|
*/
|
|
void vn_gui_logout (VnGui * obj, gboolean exit)
|
|
{
|
|
GuiData * gui_data = g_new (GuiData, 1);
|
|
gui_data->obj = g_object_ref (obj);
|
|
gui_data->aux = exit;
|
|
gui_data->error = NULL;
|
|
gui_data->thread = g_thread_new ("vn-gui-close",
|
|
(GThreadFunc) vn_gui_logout_thread, gui_data);
|
|
}
|
|
|
|
static void vn_gui_hide_form (VnWindow * window)
|
|
{
|
|
if (window->active_form)
|
|
{
|
|
GtkActionGroup * actions =
|
|
vn_form_get_action_group (window->active_form);
|
|
|
|
if (actions)
|
|
{
|
|
gtk_ui_manager_remove_ui (window->manager, window->merge_id);
|
|
gtk_ui_manager_remove_action_group (window->manager, actions);
|
|
}
|
|
|
|
window->active_form = NULL;
|
|
}
|
|
}
|
|
|
|
static void vn_gui_set_show_tabs (VnWindow * window)
|
|
{
|
|
gboolean show_tabs = gtk_notebook_get_n_pages (window->notebook) > 1
|
|
|| !gtk_toggle_action_get_active (window->dynamic_tabs);
|
|
|
|
gtk_notebook_set_show_tabs (window->notebook, show_tabs);
|
|
}
|
|
|
|
//--------------------------------------------------- Window handlers
|
|
|
|
/*
|
|
* Called when the main window is closed.
|
|
*/
|
|
gboolean vn_gui_on_main_deleted (GtkWidget * widget, GdkEvent * event, VnWindow * window)
|
|
{
|
|
vn_gui_logout (window->obj, TRUE);
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Called when a child window is closed.
|
|
*/
|
|
void vn_gui_on_child_destroyed (GtkWindow * widget, VnWindow * window)
|
|
{
|
|
VnGui * obj = window->obj;
|
|
|
|
vn_gui_free_window (obj, window);
|
|
obj->windows = g_slist_remove (obj->windows, window);
|
|
}
|
|
|
|
//--------------------------------------------------- Notebook handlers
|
|
|
|
/*
|
|
* Called when a page is detached from a notebook. This function creates a new
|
|
* window with a notebook and puts the page in.
|
|
* Connected to the "create-window" signal of GtkNotebook.
|
|
*/
|
|
GtkNotebook * vn_gui_on_page_detached (GtkNotebook * old_notebook,
|
|
GtkWidget * page, gint x, gint y, VnWindow * window)
|
|
{
|
|
VnWindow * new_window = vn_gui_create_window (window->obj, x, y);
|
|
return (window) ? new_window->notebook : NULL;
|
|
}
|
|
|
|
/*
|
|
* Called when the focus changes from a page to another. It is also used in
|
|
* newly opened pages.
|
|
*/
|
|
void vn_gui_on_switch_page (GtkNotebook * notebook, VnForm * form, guint num, VnWindow * window)
|
|
{
|
|
GError * err = NULL;
|
|
GtkTreeIter * iter;
|
|
GtkActionGroup * actions;
|
|
VnGui * obj = window->obj;
|
|
|
|
vn_gui_hide_form (window);
|
|
|
|
// Merge form UI with the window UI
|
|
|
|
window->active_form = form;
|
|
|
|
if ((iter = g_hash_table_lookup (obj->forms, vn_form_get_name (form))))
|
|
{
|
|
gchar * window_title, * form_title;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (obj->tree),
|
|
iter, COL_TITLE, &form_title, -1);
|
|
|
|
window_title = g_strdup_printf ("%s - %s", form_title, obj->app_title);
|
|
gtk_window_set_title (window->widget, window_title);
|
|
|
|
g_free (form_title);
|
|
g_free (window_title);
|
|
}
|
|
|
|
if ((actions = vn_form_get_action_group (form)))
|
|
{
|
|
guint merge_id;
|
|
const gchar * form_ui = vn_form_get_ui_manager (form);
|
|
|
|
gtk_ui_manager_insert_action_group (window->manager, actions, -1);
|
|
|
|
if ((merge_id = gtk_ui_manager_add_ui_from_string (window->manager,
|
|
form_ui, -1, &err)))
|
|
{
|
|
window->merge_id = merge_id;
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
}
|
|
}
|
|
|
|
gtk_ui_manager_ensure_update (window->manager);
|
|
}
|
|
|
|
void vn_gui_on_page_added (GtkNotebook * notebook,
|
|
GtkWidget * page, guint num, VnWindow * window)
|
|
{
|
|
vn_gui_set_show_tabs (window);
|
|
}
|
|
|
|
/*
|
|
* Called when a page of the main window is removed from its notebook.
|
|
*/
|
|
void vn_gui_on_main_page_removed (GtkNotebook * notebook,
|
|
GtkWidget * page, guint num, VnWindow * window)
|
|
{
|
|
vn_gui_set_show_tabs (window);
|
|
|
|
if (gtk_notebook_get_n_pages (notebook) < 1)
|
|
{
|
|
vn_gui_hide_form (window);
|
|
gtk_window_set_title (window->widget, window->obj->app_title);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Called when a page of a child window is removed from its notebook, if its
|
|
* the last page destroys the window too.
|
|
*/
|
|
void vn_gui_on_page_removed (GtkNotebook * notebook,
|
|
GtkWidget * page, guint num, VnWindow * window)
|
|
{
|
|
vn_gui_set_show_tabs (window);
|
|
|
|
if (gtk_notebook_get_n_pages (notebook) < 1)
|
|
gtk_widget_destroy (GTK_WIDGET (window->widget));
|
|
}
|
|
|
|
//--------------------------------------------------- Action handlers
|
|
|
|
/*
|
|
* Opens a form when the action associated to it is activated.
|
|
*/
|
|
void vn_gui_on_open_form_activated (GtkAction * action, FormData * form_data)
|
|
{
|
|
vn_gui_open_form (form_data->gui, form_data->name);
|
|
}
|
|
|
|
/*
|
|
* Reconnects to database.
|
|
*/
|
|
void vn_gui_on_open_activated (GtkAction * action, VnWindow * window)
|
|
{
|
|
vn_gui_reconnect (window->obj);
|
|
}
|
|
|
|
/*
|
|
* Logout action handler.
|
|
*/
|
|
void vn_gui_on_logout_activated (GtkAction * action, VnWindow * window)
|
|
{
|
|
vn_gui_logout (window->obj, FALSE);
|
|
}
|
|
|
|
/*
|
|
* Exit action handler.
|
|
*/
|
|
void vn_gui_on_exit_activated (GtkAction * action, VnWindow * window)
|
|
{
|
|
vn_gui_logout (window->obj, TRUE);
|
|
}
|
|
|
|
/*
|
|
* Closes the current tab when the close-tab action is activated.
|
|
*/
|
|
void vn_gui_on_close_tab_activated (GtkAction * action, VnWindow * window)
|
|
{
|
|
if (window->active_form)
|
|
vn_gui_close_form (window->obj, window->active_form);
|
|
}
|
|
|
|
/*
|
|
* Shows/hides the tabs when the view-tabs action is activated
|
|
*/
|
|
void vn_gui_on_dynamic_tabs_activated (GtkToggleAction * action, VnWindow * window)
|
|
{
|
|
vn_gui_set_show_tabs (window);
|
|
}
|
|
|
|
/*
|
|
* Shows/hides the toolbar when the view-toolbar action is activated
|
|
*/
|
|
void vn_gui_on_view_toolbar_activated (GtkToggleAction * action, VnWindow * window)
|
|
{
|
|
gtk_widget_set_visible (window->toolbar, gtk_toggle_action_get_active (action));
|
|
}
|
|
|
|
/*
|
|
* Shows a window with program information.
|
|
*/
|
|
void vn_gui_on_about_activated (GtkAction * action, VnWindow * window)
|
|
{
|
|
gtk_dialog_run (window->obj->about);
|
|
}
|
|
|
|
//--------------------------------------------------- Connection handlers
|
|
|
|
/*
|
|
* Called when there is a query error in the connection.
|
|
*/
|
|
static void vn_gui_on_conn_error (DbConn * conn, const GError * error, VnGui * obj)
|
|
{
|
|
vn_gui_show_error (obj, error);
|
|
}
|
|
|
|
/*
|
|
* Enables/disables the #GtkSpinner when connection is loading.
|
|
*/
|
|
static void vn_gui_on_conn_status_changed (DbConn * conn, DbConnStatus status, VnGui * obj)
|
|
{
|
|
gchar * status_text;
|
|
|
|
if (status & DB_CONN_CLOSING)
|
|
status_text = _("Closing connection");
|
|
else if (status & DB_CONN_TRANSACTION)
|
|
status_text = _("Transaction started");
|
|
else if (status & DB_CONN_OPENING)
|
|
status_text = _("Connecting");
|
|
else if (status & DB_CONN_LOST)
|
|
status_text = _("Connection lost");
|
|
else if (status == DB_CONN_CLOSED)
|
|
status_text = _("Connection closed");
|
|
else if (status & DB_CONN_LOADING)
|
|
status_text = _("Loading");
|
|
else
|
|
status_text = _("Ready");
|
|
|
|
gtk_label_set_text (obj->status_label, status_text);
|
|
|
|
if (status & DB_CONN_LOADING)
|
|
{
|
|
// XXX: Used to fix a bug that causes the GtkSpinner not spin.
|
|
gtk_widget_hide (GTK_WIDGET (obj->spinner));
|
|
gtk_widget_show (GTK_WIDGET (obj->spinner));
|
|
|
|
gtk_spinner_start (obj->spinner);
|
|
}
|
|
else
|
|
gtk_spinner_stop (obj->spinner);
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Public
|
|
|
|
/**
|
|
* vn_gui_open:
|
|
* @obj: a #VnGui
|
|
*
|
|
* Shows the main GUI.
|
|
**/
|
|
void vn_gui_open (VnGui * obj)
|
|
{
|
|
GtkBuilder * builder;
|
|
GError * err = NULL;
|
|
|
|
g_return_if_fail (VN_IS_GUI (obj));
|
|
g_return_if_fail (!obj->main_window);
|
|
|
|
builder = gtk_builder_new ();
|
|
|
|
if (gtk_builder_add_from_file (builder, MAIN_UI, &err))
|
|
{
|
|
gchar * user;
|
|
GtkLabel * label;
|
|
GKeyFile * config;
|
|
GtkWindow * widget;
|
|
GtkNotebook * notebook;
|
|
|
|
obj->spinner = gtk_builder_get (builder, "spinner");
|
|
obj->about = gtk_builder_get (builder, "about");
|
|
obj->menu = gtk_builder_get (builder, "menu");
|
|
obj->status_label = gtk_builder_get (builder, "status-label");
|
|
|
|
user = db_conn_get_user (obj->conn);
|
|
label = gtk_builder_get (builder, "user-name");
|
|
gtk_label_set_text (label, user);
|
|
g_free (user);
|
|
|
|
widget = gtk_builder_get (builder, "window");
|
|
notebook = gtk_builder_get (builder, "notebook");
|
|
obj->main_window = vn_gui_add_window (obj, widget, notebook);
|
|
gtk_builder_connect_signals (GTK_BUILDER (builder), obj->main_window);
|
|
|
|
// Restoring interface
|
|
|
|
config = g_key_file_new ();
|
|
|
|
if (g_key_file_load_from_file (config, obj->config_file, 0, NULL))
|
|
{
|
|
gsize m, n;
|
|
gsize len;
|
|
gint x, y;
|
|
gint width, height;
|
|
gchar ** windows;
|
|
gchar ** forms;
|
|
VnWindow * window;
|
|
|
|
windows = g_key_file_get_groups (config, &len);
|
|
|
|
for (m = 0; m < len; m++)
|
|
{
|
|
x = g_key_file_get_integer (config, windows[m], "x", NULL);
|
|
y = g_key_file_get_integer (config, windows[m], "y", NULL);
|
|
width = g_key_file_get_integer (config, windows[m], "width", NULL);
|
|
height = g_key_file_get_integer (config, windows[m], "height", NULL);
|
|
|
|
if (g_key_file_get_boolean (config, windows[m], "main", NULL))
|
|
{
|
|
window = obj->main_window;
|
|
gtk_window_move (window->widget, x, y);
|
|
}
|
|
else
|
|
window = vn_gui_create_window (obj, x, y);
|
|
|
|
gtk_window_resize (window->widget, width, height);
|
|
|
|
forms = g_key_file_get_string_list (config,
|
|
windows[m], "forms", NULL, NULL);
|
|
|
|
for (n = 0; forms[n]; n++)
|
|
vn_gui_open_form_at_window (obj, forms[n], window);
|
|
|
|
g_key_file_remove_group (config, windows[m], NULL);
|
|
g_strfreev (forms);
|
|
}
|
|
|
|
g_strfreev (windows);
|
|
}
|
|
|
|
g_key_file_free (config);
|
|
|
|
g_object_connect (obj->conn
|
|
,"signal::error", vn_gui_on_conn_error, obj
|
|
,"signal::status-changed", vn_gui_on_conn_status_changed, obj
|
|
,NULL
|
|
);
|
|
}
|
|
else if (err)
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
}
|
|
|
|
g_object_unref (builder);
|
|
}
|
|
|
|
/**
|
|
* vn_gui_save:
|
|
* @obj: the #VnGui
|
|
*
|
|
* Saves the GUI configuration.
|
|
**/
|
|
void vn_gui_save (VnGui * obj)
|
|
{
|
|
gint len;
|
|
gint j, i = 0;
|
|
gchar * group;
|
|
const gchar ** forms;
|
|
GSList * m;
|
|
GList * nb_pages, * n;
|
|
VnWindow * window;
|
|
gint x, y, width, height;
|
|
GKeyFile * config;
|
|
|
|
g_return_if_fail (VN_IS_GUI (obj));
|
|
g_return_if_fail (obj->main_window);
|
|
|
|
// Saving the interface configuration
|
|
|
|
config = g_key_file_new ();
|
|
|
|
for (m = obj->windows; m; m = m->next)
|
|
{
|
|
window = (VnWindow *) m->data;
|
|
group = g_strdup_printf ("window%d", i++);
|
|
|
|
// Saving the window position and size
|
|
|
|
gtk_window_get_position (window->widget, &x, &y);
|
|
gtk_window_get_size (window->widget, &width, &height);
|
|
|
|
g_key_file_set_integer (config, group, "x", x);
|
|
g_key_file_set_integer (config, group, "y", y);
|
|
g_key_file_set_integer (config, group, "width", width);
|
|
g_key_file_set_integer (config, group, "height", height);
|
|
|
|
// Saving the forms opened at window
|
|
|
|
if (window == obj->main_window)
|
|
g_key_file_set_boolean (config, group, "main", TRUE);
|
|
|
|
nb_pages = gtk_container_get_children (GTK_CONTAINER (window->notebook));
|
|
len = gtk_notebook_get_n_pages (window->notebook);
|
|
forms = g_new (const gchar *, len);
|
|
|
|
for (j = 0, n = nb_pages; n; n = n->next)
|
|
forms[j++] = vn_form_get_name (n->data);
|
|
|
|
g_key_file_set_string_list (config, group, "forms", forms, len);
|
|
|
|
g_list_free (nb_pages);
|
|
g_free (forms);
|
|
g_free (group);
|
|
}
|
|
|
|
gvn_key_file_save (config, obj->config_file);
|
|
g_key_file_free (config);
|
|
}
|
|
|
|
/**
|
|
* vn_gui_create_window:
|
|
* @obj: the #VnGui
|
|
* @x: the x coordinate
|
|
* @y: the y coordinate
|
|
*
|
|
* Creates a new window.
|
|
*
|
|
* Return value: VnWindow.
|
|
**/
|
|
VnWindow * vn_gui_create_window (VnGui * obj, gint x, gint y)
|
|
{
|
|
GtkBuilder * builder;
|
|
VnWindow * window = NULL;
|
|
GError * err = NULL;
|
|
|
|
g_return_val_if_fail (VN_IS_GUI (obj), NULL);
|
|
g_return_val_if_fail (obj->main_window, NULL);
|
|
|
|
builder = gtk_builder_new ();
|
|
|
|
if (gtk_builder_add_from_file (builder, CHILD_WINDOW_UI, &err))
|
|
{
|
|
GtkWindow * widget;
|
|
GtkNotebook * notebook;
|
|
|
|
widget = gtk_builder_get (builder, "child");
|
|
notebook = gtk_builder_get (builder, "notebook");
|
|
gtk_window_move (widget, x, y);
|
|
|
|
window = vn_gui_add_window (obj, widget, notebook);
|
|
gtk_builder_connect_signals (builder, window);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: %s", err->message);
|
|
g_error_free (err);
|
|
}
|
|
|
|
g_object_unref (builder);
|
|
return window;
|
|
}
|
|
|
|
/**
|
|
* vn_gui_open_form_at_window:
|
|
* @obj: the #VnGui
|
|
* @form_name: the name of the form that you want to open
|
|
* @window: the #VnWindow where the form will be opened
|
|
*
|
|
* Opens a new form at the specified window.
|
|
*
|
|
* Return value: (transfer none): the created #VnForm
|
|
**/
|
|
VnForm * vn_gui_open_form_at_window (VnGui * obj, const gchar * form_name, VnWindow * window)
|
|
{
|
|
gchar * icon;
|
|
gchar * title;
|
|
VnMod * module;
|
|
GType form_type;
|
|
GtkBox * hbox;
|
|
GtkWidget * form;
|
|
GtkWidget * widget;
|
|
GtkWidget * button;
|
|
GtkTreeIter * iter;
|
|
GtkNotebook * notebook = NULL;
|
|
|
|
g_return_val_if_fail (VN_IS_GUI (obj), NULL);
|
|
g_return_val_if_fail (obj->main_window, NULL);
|
|
|
|
iter = g_hash_table_lookup (obj->forms, form_name);
|
|
|
|
if (!iter)
|
|
{
|
|
g_warning ("VnGui: Form %s doesn't exist", form_name);
|
|
return NULL;
|
|
}
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (obj->tree), iter
|
|
,COL_ICON ,&icon
|
|
,COL_TITLE ,&title
|
|
,COL_MODULE ,&module
|
|
,COL_TYPE ,&form_type
|
|
,-1
|
|
);
|
|
|
|
form = g_object_new (form_type
|
|
,"name" ,form_name
|
|
,"gui" ,obj
|
|
,"module" ,module
|
|
,NULL
|
|
);
|
|
vn_form_open (VN_FORM (form));
|
|
|
|
hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5));
|
|
|
|
widget = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_MENU);
|
|
gtk_box_pack_start (hbox, widget, FALSE, FALSE, 0);
|
|
|
|
widget = gtk_label_new (title);
|
|
gtk_box_pack_start (hbox, widget, TRUE, TRUE, 0);
|
|
|
|
button = gtk_button_new ();
|
|
g_signal_connect (button, "clicked",
|
|
G_CALLBACK (vn_gui_close_form), form);
|
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
|
gtk_box_pack_start (hbox, button, FALSE, FALSE, 0);
|
|
|
|
widget = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_MENU);
|
|
gtk_button_set_image (GTK_BUTTON (button), widget);
|
|
|
|
if (!window)
|
|
window = vn_gui_get_active_window (obj);
|
|
|
|
notebook = window->notebook;
|
|
gtk_notebook_set_current_page (notebook,
|
|
gtk_notebook_append_page (notebook, form, GTK_WIDGET (hbox)));
|
|
gtk_notebook_set_tab_detachable (notebook, form, TRUE);
|
|
gtk_notebook_set_tab_reorderable (notebook, form, TRUE);
|
|
gtk_widget_show_all (GTK_WIDGET (hbox));
|
|
gtk_widget_show (form);
|
|
|
|
g_free (icon);
|
|
g_free (title);
|
|
|
|
return VN_FORM (form);
|
|
}
|
|
|
|
/**
|
|
* vn_gui_open_form:
|
|
* @obj: the #VnGui
|
|
* @form_name: the name of the form that you want to open
|
|
*
|
|
* Opens a new form, creating a new page for it at the main notebook.
|
|
*
|
|
* Return value: (transfer none): the created #VnForm
|
|
**/
|
|
VnForm * vn_gui_open_form (VnGui * obj, const gchar * form_name)
|
|
{
|
|
g_return_val_if_fail (VN_IS_GUI (obj), NULL);
|
|
g_return_val_if_fail (form_name, NULL);
|
|
|
|
return vn_gui_open_form_at_window (obj, form_name, NULL);
|
|
}
|
|
|
|
/**
|
|
* vn_gui_close_form:
|
|
* @obj: the #VnGui
|
|
* @form: the #VnForm that you want to close
|
|
*
|
|
* Closes a form.
|
|
**/
|
|
void vn_gui_close_form (VnGui * obj, VnForm * form)
|
|
{
|
|
gint num;
|
|
GtkNotebook * notebook;
|
|
|
|
g_return_if_fail (VN_IS_FORM (form));
|
|
|
|
notebook = GTK_NOTEBOOK (gtk_widget_get_ancestor (
|
|
GTK_WIDGET (form), GTK_TYPE_NOTEBOOK));
|
|
num = gtk_notebook_page_num (notebook, GTK_WIDGET (form));
|
|
gtk_notebook_remove_page (notebook, num);
|
|
}
|
|
|
|
/**
|
|
* vn_gui_get_conn:
|
|
* @obj: a #VnGui
|
|
*
|
|
* Gets the Data Base connection used by @obj
|
|
*
|
|
* Return value: (transfer none): the #DbConn
|
|
**/
|
|
DbConn * vn_gui_get_conn (VnGui * obj)
|
|
{
|
|
g_return_val_if_fail (VN_IS_GUI (obj), NULL);
|
|
|
|
return obj->conn;
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties
|
|
|
|
enum
|
|
{
|
|
PROP_CONN = 1
|
|
,PROP_APP
|
|
};
|
|
|
|
static void vn_gui_set_property (VnGui * obj, guint id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
switch (id)
|
|
{
|
|
case PROP_CONN:
|
|
{
|
|
gchar * query_path = g_build_path (G_SEARCHPATH_SEPARATOR_S
|
|
,_VN_MODULE_QUERY_DIR
|
|
,g_getenv ("VN_MODULE_QUERY_PATH")
|
|
,NULL
|
|
);
|
|
|
|
obj->conn = g_value_dup_object (value);
|
|
db_conn_set_query_path (obj->conn, query_path);
|
|
|
|
g_free (query_path);
|
|
break;
|
|
}
|
|
case PROP_APP:
|
|
{
|
|
gint n;
|
|
const gchar * app_id;
|
|
gchar * app_name;
|
|
gchar * config_dir;
|
|
gchar * lib_path, * data_path;
|
|
|
|
obj->app = g_value_dup_object (value);
|
|
|
|
app_id = g_application_get_application_id (G_APPLICATION (obj->app));
|
|
app_name = g_strrstr (app_id, ".") + 1;
|
|
|
|
obj->app_title = g_strdup (app_name);
|
|
obj->app_title[0] = g_ascii_toupper (obj->app_title[0]);
|
|
|
|
config_dir = g_build_filename (g_get_user_config_dir (), app_name, NULL);
|
|
g_mkdir_with_parents (config_dir, 0700);
|
|
obj->config_file = g_build_filename (config_dir, "gui.ini", NULL);
|
|
g_free (config_dir);
|
|
|
|
// Setting module search paths
|
|
|
|
lib_path = g_build_path (G_SEARCHPATH_SEPARATOR_S
|
|
,_VN_MODULE_LIB_DIR
|
|
,g_getenv ("VN_MODULE_LIB_PATH")
|
|
,NULL
|
|
);
|
|
data_path = g_build_path (G_SEARCHPATH_SEPARATOR_S
|
|
,_VN_MODULE_DATA_DIR
|
|
,g_getenv ("VN_MODULE_DATA_PATH")
|
|
,NULL
|
|
);
|
|
|
|
obj->lib_dirs = g_strsplit (lib_path, G_SEARCHPATH_SEPARATOR_S, 0);
|
|
obj->data_dirs = g_strsplit (data_path, G_SEARCHPATH_SEPARATOR_S, 0);
|
|
|
|
g_free (data_path);
|
|
g_free (lib_path);
|
|
|
|
// Initializing modules
|
|
|
|
for (n = 0; obj->data_dirs[n]; n++)
|
|
{
|
|
const gchar * file;
|
|
GError * err = NULL;
|
|
GDir * dir = g_dir_open (obj->data_dirs[n], 0, &err);
|
|
|
|
if (dir)
|
|
{
|
|
while ((file = g_dir_read_name (dir)))
|
|
if (!g_strcmp0 (".xml", g_strrstr (file, ".")))
|
|
vn_gui_load_module (obj, obj->data_dirs[n], file);
|
|
|
|
g_dir_close (dir);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("VnGui: Error opening directory at module data path: %s"
|
|
,err->message
|
|
);
|
|
g_error_free (err);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
|
|
}
|
|
}
|
|
|
|
static void vn_gui_get_property (VnGui * obj, guint id,
|
|
GValue * value, GParamSpec * pspec)
|
|
{
|
|
switch (id)
|
|
{
|
|
case PROP_CONN:
|
|
g_value_set_object (value, obj->conn);
|
|
break;
|
|
case PROP_APP:
|
|
g_value_set_object (value, obj->app);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
|
|
}
|
|
}
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class
|
|
|
|
static void vn_gui_init (VnGui * obj)
|
|
{
|
|
obj->main_window = NULL;
|
|
obj->about = NULL;
|
|
obj->windows = NULL;
|
|
obj->conn = NULL;
|
|
obj->app = NULL;
|
|
obj->app_title = NULL;
|
|
obj->modules = NULL;
|
|
obj->lib_dirs = NULL;
|
|
obj->data_dirs = NULL;
|
|
obj->config_file = NULL;
|
|
|
|
obj->forms = g_hash_table_new_full (
|
|
(GHashFunc) g_str_hash
|
|
,(GEqualFunc) g_str_equal
|
|
,(GDestroyNotify) g_free
|
|
,(GDestroyNotify) g_free
|
|
);
|
|
obj->tree = gtk_tree_store_new (COL_COUNT
|
|
,G_TYPE_STRING // COL_ICON
|
|
,G_TYPE_STRING // COL_NAME
|
|
,G_TYPE_STRING // COL_TITLE
|
|
,G_TYPE_GTYPE // COL_TYPE
|
|
,G_TYPE_OBJECT // COL_MODULE
|
|
);
|
|
}
|
|
|
|
static void vn_gui_finalize (VnGui * obj)
|
|
{
|
|
vn_gui_close (obj);
|
|
db_conn_close (obj->conn, FALSE);
|
|
|
|
g_hash_table_unref (obj->forms);
|
|
g_slist_free_full (obj->modules, (GDestroyNotify) vn_gui_free_mod_data);
|
|
g_clear_object (&obj->conn);
|
|
g_clear_object (&obj->tree);
|
|
g_clear_object (&obj->app);
|
|
g_strfreev (obj->lib_dirs);
|
|
g_strfreev (obj->data_dirs);
|
|
g_free (obj->config_file);
|
|
g_free (obj->app_title);
|
|
G_OBJECT_CLASS (vn_gui_parent_class)->finalize (G_OBJECT (obj));
|
|
}
|
|
|
|
static void vn_gui_class_init (VnGuiClass * k)
|
|
{
|
|
GObjectClass * klass = G_OBJECT_CLASS (k);
|
|
klass->finalize = (GObjectFinalizeFunc) vn_gui_finalize;
|
|
klass->set_property = (GObjectSetPropertyFunc) vn_gui_set_property;
|
|
klass->get_property = (GObjectGetPropertyFunc) vn_gui_get_property;
|
|
|
|
signals[LOGOUT] = g_signal_new ("logout",
|
|
VN_TYPE_GUI, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0
|
|
);
|
|
signals[EXIT] = g_signal_new ("exit",
|
|
VN_TYPE_GUI, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0
|
|
);
|
|
|
|
g_object_class_install_property (klass, PROP_CONN,
|
|
g_param_spec_object ("conn"
|
|
,_("Connection")
|
|
,_("The connection used by Gui")
|
|
,DB_TYPE_CONN
|
|
,G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
|
|
));
|
|
g_object_class_install_property (klass, PROP_APP,
|
|
g_param_spec_object ("app"
|
|
,_("Application")
|
|
,_("The application handler for the entire program")
|
|
,GTK_TYPE_APPLICATION
|
|
,G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY
|
|
));
|
|
}
|