[gcompris: 2/9] Sugar sharing and additional Journal integration (sugar part)
- From: Bruno Coudoin <bcoudoin src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcompris: 2/9] Sugar sharing and additional Journal integration (sugar part)
- Date: Sun, 20 May 2012 00:06:00 +0000 (UTC)
commit fbe4e69ea33034c8d046637312a2b73b8ebb1879
Author: Aleksey Lim <alsroot sugarlabs org>
Date: Sat Mar 10 03:58:24 2012 +0000
Sugar sharing and additional Journal integration (sugar part)
src/gcompris/Makefile.am | 11 +-
src/gcompris/sugar.c | 546 ++++++++++++------------
src/gcompris/sugar.h | 43 ++
src/gcompris/sugar_cli.c | 389 ++++++++++++++++
src/gcompris/sugar_db.c | 479 ++++++++++++++++++++
src/gcompris/sugar_db.h | 49 ++
src/gcompris/sugar_gc.c | 441 +++++++++++++++++++
src/gcompris/sugar_gc.h | 79 ++++
src/gcompris/sugar_share.c | 977 +++++++++++++++++++++++++++++++++++++++++
src/gcompris/sugar_share.h | 113 +++++
src/gcompris/sugar_share.vala | 186 ++++++++
src/gcompris/sugar_srv.c | 160 +++++++
12 files changed, 3199 insertions(+), 274 deletions(-)
---
diff --git a/src/gcompris/Makefile.am b/src/gcompris/Makefile.am
index cf87969..3b947ff 100644
--- a/src/gcompris/Makefile.am
+++ b/src/gcompris/Makefile.am
@@ -142,6 +142,15 @@ DONT_DIST_SOURCE = $(marshal_sources)
if SUGAR
INCLUDES += $(SUGAR_CFLAGS)
-gcompris_SOURCES += sugar.c
+gcompris_SOURCES += \
+ sugar.c sugar.h \
+ sugar_gc.c sugar_gc.h \
+ sugar_cli.c \
+ sugar_srv.c \
+ sugar_share.c sugar_share.h \
+ sugar_db.h
gcompris_LDADD += $(SUGAR_LIBS)
+if USE_SQLITE
+gcompris_SOURCES += sugar_db.c
+endif
endif
diff --git a/src/gcompris/sugar.c b/src/gcompris/sugar.c
index ba37868..596f3da 100644
--- a/src/gcompris/sugar.c
+++ b/src/gcompris/sugar.c
@@ -16,356 +16,356 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include <sugar/toolkit.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <gdk/gdkx.h>
+#include <dbus/dbus-glib.h>
+
+#include <polyol/toolkit.h>
#include "gcompris.h"
#include "gc_core.h"
#include "bar.h"
#include "score.h"
-
-static void bar_start(GtkContainer*, GooCanvas*);
-static void bar_set_level(GcomprisBoard*);
-static void bar_set_flags(const GComprisBarFlags);
-static void score_start(ScoreStyleList, guint, guint, guint);
-static void score_end();
-static void score_set(guint);
-static void help_clicked_cb(GtkToolButton*, gpointer);
-static void about_clicked_cb(GtkToolButton*, gpointer);
-static void level_clicked_cb(GtkToolButton*, gpointer);
-static void refresh_clicked_cb(GtkToolButton*, gpointer);
-static void zoom_clicked_cb(GtkToolButton*, gpointer);
-static void config_clicked_cb(GtkToolButton*, gpointer);
-static void back_clicked_cb(GtkToolButton*, gpointer);
-static void stop_clicked_cb(GtkToolButton*, gpointer);
-static GtkToolItem* level_widget_new();
-static GtkToolItem* score_widget_new();
-static GtkToolItem* expander_new();
-static GtkToolItem* separator_new();
-
-/* export sugar bar */
-Bar sugar_bar = {
- bar_start,
- bar_set_level,
- NULL,
- NULL,
- bar_set_flags,
- NULL
+#include "status.h"
+#include "sugar.h"
+#include "sugar_db.h"
+#include "sugar_share.h"
+
+#define JOURNAL_PREFIX "journal:"
+
+static const gchar *jobject_mime_types[][2] = {
+ {GC_MIME_TYPE "-wordprocessor", "/fun/wordprocessor"},
+ {GC_MIME_TYPE "-anim", "/fun/anim"},
+ {GC_MIME_TYPE "-draw", "/fun/draw"},
+ {NULL, NULL}
};
-/* export sugar score */
-Score sugar_score = {
- score_start,
- score_end,
- score_set
- score_set_max,
-};
+static void notify_active_cb(GObject*);
+static void chooser_response_cb(GObject*, const gchar*);
-typedef struct {
- const gchar *icon;
- const gchar *label;
- gpointer cb;
- gpointer user_data;
-} Button;
-
-static Button buttons[] = {
- { "emblem-question", N_("Help"), help_clicked_cb, NULL },
- { "stock_home", N_("About"), about_clicked_cb, NULL },
- { "go-previous-paired", N_("Previous level"), level_clicked_cb,
- GINT_TO_POINTER(-1) },
- { NULL, NULL, level_widget_new, NULL },
- { "go-next-paired", N_("Next level"), level_clicked_cb,
- GINT_TO_POINTER(+1) },
- { "stock_refresh", N_("Refresh"), refresh_clicked_cb, NULL },
- { "preferences-system", N_("Settings"), config_clicked_cb, NULL },
- { NULL, NULL, expander_new, NULL },
- { NULL, NULL, score_widget_new, NULL },
- { NULL, NULL, expander_new, NULL },
- { "view-fullscreen", N_("Zoom"), zoom_clicked_cb, NULL },
- { NULL, NULL, separator_new, NULL },
- { "go-previous",
- /* TRANSLATORS: Back as in previous */
- N_("Back"), back_clicked_cb, NULL },
- { "activity-stop", N_("Stop"), stop_clicked_cb, NULL }
-};
+SugarActivity *activity;
+SugarJobject *board_jobject;
-enum {
- BUTTON_HELP = 0,
- BUTTON_ABOUT,
- BUTTON_PREV,
- BUTTON_LEVEL,
- BUTTON_NEXT,
- BUTTON_REFRESH,
- BUTTON_CONFIG,
- BUTTON_EXPANDER_1,
- BUTTON_SCORE,
- BUTTON_EXPANDER_2,
- BUTTON_ZOOM,
- BUTTON_SEPARATOR,
- BUTTON_BACK,
- BUTTON_STOP,
- BUTTONS_COUNT
-};
+static SugarJobject *journal_file_object;
+static ImageSelectorCallBack choose_image_cb;
+static void * choose_image_user_context;
+static const gchar *jobject_mime_type;
-static gint16 buttons_mask;
-static GtkToolItem *button_widgets[BUTTONS_COUNT];
-static GtkToolbar *toolbar;
-static SugarToolkitToolText *level_widget;
-static SugarToolkitToolText *score_widget;
-static gint current_level = -1;
-static gint max_score;
+extern Peer srv_peer;
+extern Peer cli_peer;
+static Peer empty_peer;
+static Peer *peer = &empty_peer;
+static gboolean initial_activate = TRUE;
-static void
-bar_start(GtkContainer *workspace, GooCanvas *theCanvas)
-{
- SugarToolkitToolbarBox *toolbox = sugar_toolkit_toolbar_box_new(-1);
- gtk_box_pack_start(GTK_BOX(workspace), GTK_WIDGET(toolbox), FALSE, TRUE, 0);
- toolbar = sugar_toolkit_toolbar_box_get_toolbar(toolbox);
- gtk_widget_show(GTK_WIDGET(toolbar));
- current_level = 1;
-}
+extern Bar sugar_bar;
+extern Score sugar_score;
-static void
-set_button(gint number, gboolean visible)
+void
+sugar_setup(int *argc, char ***argv)
{
- Button *button = &buttons[number];
- GtkToolItem *item = button_widgets[number];
-
- if (item == NULL) {
- if (button->icon == NULL)
- item = ((GtkToolItem* (*)(void))button->cb)();
- else {
- item = gtk_tool_button_new(NULL, button->label);
- gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(item), button->icon);
- g_signal_connect(item, "clicked", G_CALLBACK(button->cb),
- button->user_data);
- }
+ if (!sugar_init(argv, argc))
+ return;
- g_object_ref_sink(item);
- button_widgets[number] = item;
+ g_debug("Use sugar mode");
+
+ if (strcmp("net.gcompris.administration",
+ sugar_environ_get_bundle_id()) == 0)
+ {
+ /* There should be only one bundle_id for GCompris objects in
+ non-MODE_STANDALONE_ACTIVITY mode to let teacher via Administration
+ activity and students via GCompris activity share the same objects */
+ (*argv)[(*argc)++] = "-b";
+ (*argv)[(*argc)++] = "net.gcompris";
+ (*argv)[*argc] = NULL;
+ sugar_init(argv, argc);
}
- if (visible) {
- if (gtk_widget_get_parent(GTK_WIDGET(item)) == NULL) {
- int i;
- int item_pos = 0;
- for (i = 0; i < number; ++i)
- if (buttons_mask & (1 << i))
- ++item_pos;
-
- gtk_widget_show(GTK_WIDGET(item));
- gtk_toolbar_insert(toolbar, item, item_pos);
- buttons_mask |= (1 << number);
- }
- } else {
- if (gtk_widget_get_parent(GTK_WIDGET(item))) {
- gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(item));
- buttons_mask &= ~(1 << number);
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+ dbus_g_thread_init ();
+
+ sugar_environ_set_sync_dbus(TRUE);
+
+ const gchar *resumed_jobject_id = sugar_environ_get_object_id();
+ if (resumed_jobject_id)
+ {
+ SugarJobject *resumed_jobject = sugar_jobject_find(resumed_jobject_id);
+ if (resumed_jobject)
+ {
+ const gchar *mime_type = sugar_jobject_get_mime_type(resumed_jobject);
+ const gchar *(*i)[2];
+ for (i = jobject_mime_types; (*i)[0]; ++i)
+ {
+ if (strcmp((*i)[0], mime_type) == 0)
+ {
+ jobject_mime_type = (*i)[1];
+ g_debug("Start activity %s", jobject_mime_type);
+ break;
+ }
+ }
}
}
}
-static void
-update_level()
+gboolean
+sugar_detected()
{
- gchar level_string[256];
- snprintf(level_string, sizeof(level_string), "%d", current_level);
- g_object_set(level_widget, "text", level_string, NULL);
+ return sugar_environ_get_initialized();
}
-static void
-update_score(guint value)
+const gchar *
+sugar_jobject_root_menu(void)
{
- gchar score_string[256];
- snprintf(score_string, sizeof(score_string), "%d/%d", value, max_score);
- g_object_set(score_widget, "text", score_string, NULL);
+ return jobject_mime_type;
}
-static GtkToolItem*
-level_widget_new()
+void
+sugar_setup_profile(const gchar *root, gboolean administration)
{
- g_assert(level_widget == NULL);
- level_widget = sugar_toolkit_tool_text_new();
- update_level();
- return GTK_TOOL_ITEM(level_widget);
-}
+ if (!sugar_detected())
+ return;
-static GtkToolItem*
-score_widget_new()
-{
- g_assert(score_widget == NULL);
- score_widget = sugar_toolkit_tool_text_new();
- return GTK_TOOL_ITEM(score_widget);
-}
+ activity = sugar_activity_new (TRUE, !jobject_mime_type);
-static GtkToolItem*
-separator_new()
-{
- GtkToolItem *separator = gtk_separator_tool_item_new();
- gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(separator), FALSE);
- return separator;
-}
+ g_debug("Setup sugar profile root=%s administration=%d ",
+ root, administration);
-static GtkToolItem*
-expander_new()
-{
- GtkToolItem *expander = gtk_separator_tool_item_new();
- gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(expander), FALSE);
- gtk_tool_item_set_expand(GTK_TOOL_ITEM(expander), TRUE);
- return expander;
-}
+ SugarJobject *jobject = sugar_activity_get_jobject(activity);
-static void
-beep()
-{
- gc_sound_play_ogg("sounds/bleep.wav", NULL);
-}
+ if (!sugar_activity_get_resumed(activity))
+ {
+ if (!jobject_mime_type)
+ sugar_jobject_set_mime_type(jobject, GC_MIME_TYPE);
+ else
+ {
+ gchar *activity_name = strrchr(root, '/') + 1;
+ gchar *mime = g_strdup_printf("%s-%s", GC_MIME_TYPE, activity_name);
+ sugar_jobject_set_mime_type(jobject, mime);
+ g_free(mime);
+ }
+ }
-static void
-help_clicked_cb(GtkToolButton *button, gpointer user_data)
-{
- beep();
- GcomprisBoard *board = gc_board_get_current();
- gc_help_start(board);
+ if (!jobject_mime_type)
+ {
+ if (administration)
+ peer = &srv_peer;
+ else
+ peer = &cli_peer;
+ }
+
+ g_signal_connect(sugar_activity_get_shell(activity), "notify::active",
+ G_CALLBACK(notify_active_cb), NULL);
+ g_signal_connect(sugar_activity_get_journal(activity), "chooser-response",
+ G_CALLBACK(chooser_response_cb), NULL);
+
+ gc_bar_register(&sugar_bar);
+ gc_score_register(&sugar_score);
+
+ if (peer->construct)
+ peer->construct();
}
-static void
-about_clicked_cb(GtkToolButton *button, gpointer user_data)
+void
+sugar_setup_x11()
{
- beep();
- gc_about_start();
+ GtkWidget *window = gc_get_window();
+ Window xwindow = GDK_WINDOW_XWINDOW(window->window);
+ sugar_environ_set_window(GDK_DISPLAY(), xwindow);
}
-static void
-level_clicked_cb(GtkToolButton *button, gpointer user_data)
+void
+sugar_cleanup()
{
- beep();
-
- GcomprisBoard *board = gc_board_get_current();
- if (board == NULL)
- return;
-
- gint delta = GPOINTER_TO_INT(user_data);
- current_level += delta;
+ if (!sugar_detected())
+ return;
- if (current_level > board->maxlevel)
- current_level = 1;
- else if (current_level < 1)
- current_level = board->maxlevel;
+ g_debug("Cleanup sugar mode");
- update_level();
+ if (peer->finalize)
+ peer->finalize();
- if (board->plugin->set_level != NULL)
- board->plugin->set_level(current_level);
+ if (board_jobject != NULL)
+ g_object_unref(G_OBJECT(board_jobject));
+ board_jobject = NULL;
- gc_bar_play_level_voice(current_level);
-}
+ if(journal_file_object != NULL)
+ g_object_unref(G_OBJECT(journal_file_object));
+ journal_file_object = NULL;
-static void
-refresh_clicked_cb(GtkToolButton *button, gpointer user_data)
-{
- beep();
- GcomprisBoard *board = gc_board_get_current();
- if(board && board->plugin->repeat != NULL)
- board->plugin->repeat();
+ g_object_unref(G_OBJECT(activity));
+ activity = NULL;
}
-static void
-zoom_clicked_cb(GtkToolButton *button, gpointer user_data)
+const char *
+sugar_load(void)
{
- beep();
- GcomprisProperties *properties = gc_prop_get();
- properties->zoom = (properties->zoom ? 0 : 1);
- gc_update_canvas_zoom();
-}
+ if (!sugar_detected())
+ return NULL;
-static void
-config_clicked_cb(GtkToolButton *button, gpointer user_data)
-{
- beep();
- GcomprisBoard *board = gc_board_get_current();
- if(board && board->plugin->config_start != NULL)
- board->plugin->config_start(board, gc_profile_get_current());
-}
+ switch_board_jobject();
-static void
-back_clicked_cb(GtkToolButton *button, gpointer user_data)
-{
- gc_board_stop();
-}
+ const char *file_path = sugar_jobject_get_file_path(board_jobject);
-static void
-stop_clicked_cb(GtkToolButton *button, gpointer user_data)
-{
- // save zoom setting
- GcomprisProperties *properties = gc_prop_get();
- gc_prop_save(properties);
+ if (file_path != NULL)
+ g_debug("Load file from %s", sugar_jobject_get_uid(board_jobject));
- gc_exit();
+ return file_path;
}
-static void
-bar_set_flags(const GComprisBarFlags flags)
+void
+sugar_save(const char *path)
{
- GcomprisBoard *board = gc_board_get_current();
+ GError *error = NULL;
+ GArray *preview = NULL;
- set_button(BUTTON_HELP, flags & GC_BAR_HELP || gc_help_has_board(board));
- set_button(BUTTON_ABOUT, flags & GC_BAR_ABOUT);
+ if (!sugar_detected())
+ return;
- set_button(BUTTON_PREV, flags & GC_BAR_LEVEL);
- set_button(BUTTON_LEVEL, flags & GC_BAR_LEVEL);
- set_button(BUTTON_NEXT, flags & GC_BAR_LEVEL);
+ switch_board_jobject();
- set_button(BUTTON_REFRESH, flags & (GC_BAR_REPEAT | GC_BAR_REPEAT_ICON));
- set_button(BUTTON_CONFIG, flags & GC_BAR_CONFIG);
+ preview = sugar_get_preview(&error);
+ if (preview != NULL)
+ {
+ sugar_jobject_set_preview(board_jobject, preview);
+ g_array_free(preview, FALSE);
+ } else {
+ g_warning("Cannot get preview: %s", error->message);
+ g_error_free(error);
+ }
- set_button(BUTTON_EXPANDER_1, TRUE);
- set_button(BUTTON_SCORE, max_score);
- set_button(BUTTON_EXPANDER_2, TRUE);
+ sugar_jobject_write_file(board_jobject, path, TRUE);
- set_button(BUTTON_ZOOM, TRUE);
- set_button(BUTTON_SEPARATOR, TRUE);
- set_button(BUTTON_BACK, board && board->previous_board);
- set_button(BUTTON_STOP, TRUE);
+ if (peer->save_jobject)
+ peer->save_jobject(board_jobject);
+
+ g_warning("%p Saved %s file to journal entry %s", board_jobject, path,
+ sugar_jobject_get_uid(board_jobject));
}
-static void
-score_start(ScoreStyleList style, guint x, guint y, guint max)
+void
+sugar_choose_image(ImageSelectorCallBack iscb, void *user_context)
{
- max_score = max;
- set_button(BUTTON_SCORE, TRUE);
- update_score(0);
+ choose_image_cb = iscb;
+ choose_image_user_context = user_context;
+ sugar_journal_choose_object(sugar_activity_get_journal(activity),
+ SUGAR_MIME_IMAGE);
}
-static void
-score_end()
+gchar *
+sugar_get_journal_file(gchar *file_id)
{
- max_score = 0;
- set_button(BUTTON_SCORE, FALSE);
+ if(!g_str_has_prefix(file_id, JOURNAL_PREFIX))
+ return file_id;
+
+ gchar *file_path = NULL;
+ const gchar *object_id = file_id + strlen(JOURNAL_PREFIX);
+
+ if(journal_file_object != NULL)
+ g_object_unref(G_OBJECT(journal_file_object));
+ journal_file_object = sugar_jobject_find(object_id);
+
+ if(journal_file_object == NULL)
+ g_warning("Cannot find jobject %s", object_id);
+ else
+ {
+ file_path = g_strdup(sugar_jobject_get_file_path(journal_file_object));
+ if(file_path == NULL)
+ g_warning("Cannot get file from jobject %s", object_id);
+ }
+
+ g_free(file_id);
+ return file_path;
}
static void
-score_set(guint value)
+notify_active_cb(GObject *sender)
{
- update_score(value);
+ SugarShell *shell = sugar_activity_get_shell(activity);
+ gboolean active = sugar_shell_get_active(shell);
+
+ g_debug("SugarShell.active=%d", active);
+
+ if(!active)
+ gc_sound_close();
+ else if(initial_activate == FALSE)
+ gc_sound_reopen();
+
+ initial_activate = FALSE;
}
static void
-score_set_max(guint max)
+chooser_response_cb(GObject *sender, const gchar *object_id)
{
- max_score = max;
+ g_debug("SugarShell.chooser_response_cb=%s", object_id);
+
+ if(choose_image_cb != NULL && object_id != NULL)
+ {
+ gchar file_id[256];
+ snprintf(file_id, sizeof(file_id), "%s%s", JOURNAL_PREFIX, object_id);
+ choose_image_cb(file_id, choose_image_user_context);
+ choose_image_cb = NULL;
+ }
}
-static void
-bar_set_level(GcomprisBoard *board)
+gboolean
+switch_board_jobject()
{
- if (board == NULL)
- return;
+ static GcomprisBoard *board = NULL;
+
+ if (board == gc_board_get_current())
+ return FALSE;
- if (level_widget == NULL) {
- g_message("in bar_set_level, level_item uninitialized : should not happen\n");
+ board = gc_board_get_current();
+ SugarJobject *new_board_jobject = NULL;
+
+ if (peer->get_jobject && is_activity_board())
+ new_board_jobject = peer->get_jobject(board);
+ else
+ {
+ new_board_jobject = sugar_activity_get_jobject(activity);
+ g_object_ref(G_OBJECT(new_board_jobject));
+ }
+
+ gboolean result = (new_board_jobject != board_jobject);
+ if (board_jobject)
+ g_object_unref(board_jobject);
+ board_jobject = new_board_jobject;
+
+ return result;
+}
+
+void
+save_profile(GKeyFile *profile)
+{
+ char tmp_file[] = "/tmp/GComprisXXXXXX";
+ int fd = mkstemp(tmp_file);
+ if (fd == -1)
+ {
+ g_warning("Cannot create temporary file to save");
return;
}
- current_level = board->level;
- update_level();
+ gsize size = 0;
+ gchar *profile_data = g_key_file_to_data(profile, &size, NULL);
+ gboolean success = (write(fd, profile_data, size) == size);
+ g_free(profile_data);
+ fchmod(fd, 0644);
+ close(fd);
+
+ if (success)
+ sugar_activity_write_file(activity, tmp_file, TRUE);
+ else
+ {
+ unlink(tmp_file);
+ g_warning("Cannot save profile to journal entry");
+ }
+}
+
+gboolean
+is_activity_board()
+{
+ GcomprisBoard *board = gc_board_get_current();
+ return board->name[0] != '\0' && strcmp("login", board->name) != 0 &&
+ strcmp("administration", board->name) != 0;
}
diff --git a/src/gcompris/sugar.h b/src/gcompris/sugar.h
new file mode 100644
index 0000000..cb84e3b
--- /dev/null
+++ b/src/gcompris/sugar.h
@@ -0,0 +1,43 @@
+/* gcompris - sugar.h
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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/>.
+ */
+
+#ifndef SUGAR_H
+#define SUGAR_H
+
+#define GC_MIME_TYPE "application/x-gcompris"
+
+void save_profile(GKeyFile*);
+gboolean switch_board_jobject();
+gboolean is_activity_board();
+
+extern SugarActivity *activity;
+extern SugarJobject *board_jobject;
+
+typedef void (*Callback)(void);
+typedef SugarJobject *(*GetJobjectCallback)(GcomprisBoard*);
+typedef void (*SaveJobjectCallback)(SugarJobject*);
+
+typedef struct
+{
+ Callback construct;
+ Callback finalize;
+ GetJobjectCallback get_jobject;
+ SaveJobjectCallback save_jobject;
+} Peer;
+
+#endif
diff --git a/src/gcompris/sugar_cli.c b/src/gcompris/sugar_cli.c
new file mode 100644
index 0000000..bbfa08b
--- /dev/null
+++ b/src/gcompris/sugar_cli.c
@@ -0,0 +1,389 @@
+/* gcompris - sugar_cli.c
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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 <polyol/toolkit.h>
+
+#include "gcompris.h"
+#include "gc_core.h"
+#include "status.h"
+#include "sugar.h"
+#include "sugar_share.h"
+
+static void construct();
+static void finalize();
+static void load_profile();
+static void setup_gc_profile();
+static void scope_changed_cb(SugarConnection*, SugarShareScope, const gchar*);
+static void channel_appeared_cb(SugarConnection*, SugarChannel*);
+static void buddy_appeared_cb(SugarChannel*, guint, const gchar*);
+static void buddy_disappeared_cb(SugarChannel*, guint, const gchar*);
+static void get_profile_from_server_cb(const char*, void*);
+static void load_board(gchar*, gint);
+static void finalize_delayed_start();
+static SugarJobject *get_jobject(GcomprisBoard*);
+static void save_jobject(SugarJobject*);
+
+static GKeyFile *profile;
+static AdministrationClient *client;
+static gboolean delayed_start;
+
+Peer cli_peer = {
+ construct,
+ finalize,
+ get_jobject,
+ save_jobject
+};
+
+gboolean
+sugar_delayed_start(void)
+{
+ return delayed_start;
+}
+
+void
+sugar_report(const gchar *date, guint duration, const gchar *user,
+ GcomprisBoard *board, GCBonusStatusList status, const gchar *comment)
+{
+ gchar *user_section = g_strdup_printf("user/%s", user);
+ gchar *report_section = g_strdup_printf("report/%s/%s", date, board->name);
+
+ if (client != NULL)
+ administration_client_report(client, date, duration, user,
+ board->name, board->level, board->sublevel, (int) status, comment);
+
+ g_key_file_set_string(profile, report_section, "date", date);
+ g_key_file_set_integer(profile, report_section, "duration", duration);
+ g_key_file_set_string(profile, report_section, "user", user_section);
+ g_key_file_set_string(profile, report_section, "board", board->name);
+ g_key_file_set_integer(profile, report_section, "level", board->level);
+ g_key_file_set_integer(profile, report_section, "sublevel", board->sublevel);
+ g_key_file_set_integer(profile, report_section, "status", (int)status);
+ g_key_file_set_string(profile, report_section, "comment", comment);
+
+ g_free(report_section);
+ g_free(user_section);
+}
+
+static void
+construct()
+{
+ profile = g_key_file_new();
+
+ SugarConnection *conn = sugar_activity_get_connection(activity);
+
+ g_signal_connect(conn, "scope-changed", G_CALLBACK(scope_changed_cb), NULL);
+ g_signal_connect(conn, "channel-appeared", G_CALLBACK(channel_appeared_cb),
+ NULL);
+
+ if (sugar_connection_get_scope(conn) == SUGAR_SHARE_SCOPE_PRIVATE ||
+ !sugar_connection_get_shared(conn) ||
+ sugar_connection_get_initiator(conn))
+ load_profile();
+ else
+ delayed_start = TRUE;
+}
+
+static void
+finalize()
+{
+ if (client != NULL)
+ administration_client_unref(client);
+ client = NULL;
+
+ if (!delayed_start)
+ save_profile(profile);
+
+ g_key_file_free(profile);
+ profile = NULL;
+}
+
+static SugarJobject *
+get_jobject(GcomprisBoard *board)
+{
+ SugarJobject *jobject = NULL;
+
+ gchar *object_id = g_key_file_get_string(profile, "jobjects",
+ board->name, NULL);
+ if (object_id != NULL)
+ {
+ jobject = sugar_jobject_find(object_id);
+ g_free(object_id);
+ }
+
+ if (jobject == NULL)
+ {
+ jobject = sugar_jobject_create();
+ gchar *bundle_id = g_strdup_printf("net.gcompris.%s", board->name);
+ sugar_jobject_set_activity(jobject, bundle_id);
+ gchar *mime = g_strdup_printf("%s-%s", GC_MIME_TYPE, board->name);
+ sugar_jobject_set_mime_type(jobject, mime);
+ g_free(bundle_id);
+ g_free(mime);
+ }
+
+ return jobject;
+}
+
+static void
+save_jobject(SugarJobject *jobject)
+{
+ g_key_file_set_string(profile, "jobjects", gc_board_get_current()->name,
+ sugar_jobject_get_uid(jobject));
+}
+
+static void
+scope_changed_cb(SugarConnection *conn, SugarShareScope prev_scope,
+ const gchar *error)
+{
+ if (sugar_connection_get_scope(conn) == SUGAR_SHARE_SCOPE_PRIVATE)
+ {
+ if (client != NULL)
+ administration_client_unref(client);
+ client = NULL;
+
+ if (delayed_start)
+ {
+ load_profile();
+ finalize_delayed_start();
+ }
+ }
+}
+
+static void
+channel_appeared_cb(SugarConnection *conn, SugarChannel *channel)
+{
+ g_signal_connect(channel, "buddy-appeared",
+ G_CALLBACK(buddy_appeared_cb), NULL);
+ g_signal_connect(channel, "buddy-disappeared",
+ G_CALLBACK(buddy_disappeared_cb), NULL);
+
+ g_debug ("Wait for server");
+}
+
+static void
+buddy_appeared_cb(SugarChannel *channel, guint buddy, const gchar *bus_name)
+{
+ if (client == NULL && sugar_channel_get_owner(channel) == buddy)
+ {
+ const gchar *address = sugar_channel_get_address(channel);
+ client = administration_client_new(address, bus_name,
+ get_profile_from_server_cb, NULL);
+
+ g_debug ("Connected to server %s", bus_name);
+
+ if (delayed_start)
+ administration_client_import_profile(client);
+ }
+}
+
+static void
+buddy_disappeared_cb(SugarChannel *channel, guint buddy, const gchar *bus_name)
+{
+ if (client != NULL && sugar_channel_get_owner(channel) == buddy)
+ {
+ g_debug ("Disconnected from server %s", bus_name);
+ administration_client_unref(client);
+ client = NULL;
+ }
+}
+
+static void
+get_profile_from_server_cb(const char* profile_data, void* user_data)
+{
+ if (profile_data != NULL)
+ {
+ GError *error;
+ if (!g_key_file_load_from_data(profile, profile_data, strlen(profile_data),
+ G_KEY_FILE_NONE, &error))
+ {
+ profile_data = NULL;
+ g_warning("Cannot import server profile: %s", error->message);
+ g_error_free(error);
+ }
+ }
+
+ if (profile_data == NULL)
+ {
+ SugarAlert *alert = SUGAR_ALERT(sugar_notify_alert_new(_("Sharing Error"),
+ _("Cannot retrieve remote data"), "emblem-warning", 7));
+ sugar_alert_bin_push(alert);
+
+ SugarConnection *conn = sugar_activity_get_connection(activity);
+ sugar_connection_set_scope(conn, SUGAR_SHARE_SCOPE_PRIVATE);
+ }
+
+ if (delayed_start)
+ {
+ if (profile_data == NULL)
+ load_profile();
+ else
+ setup_gc_profile();
+ finalize_delayed_start();
+ }
+}
+
+static void
+finalize_delayed_start()
+{
+ GcomprisProperties *properties = gc_prop_get();
+ GcomprisBoard *board;
+
+ g_debug("Delayed start");
+
+ delayed_start = FALSE;
+
+ gc_menu_load();
+ gc_status_close();
+
+ properties->menu_board = gc_menu_section_get("/");
+ if (properties->profile == NULL || properties->profile->group_ids == NULL)
+ board = gc_menu_section_get("/");
+ else
+ board = gc_menu_section_get("/login/login");
+ gc_board_play(board);
+}
+
+static void
+setup_gc_profile()
+{
+ int i, j;
+ gchar **board_files = g_key_file_get_string_list(profile,
+ "profile", "boards", NULL, NULL);
+
+ if (!board_files)
+ return;
+
+ GcomprisProfile *gc_profile = g_malloc0(sizeof(GcomprisProfile));
+ gc_prop_get()->profile = gc_profile;
+
+ gc_profile->profile_id = 0;
+ gc_profile->name = g_strdup("Sugar Profile");
+ gc_profile->directory = g_strdup(sugar_environ_get_activity_root());
+ gc_profile->description = g_strdup("Sugar Journal Object");
+ gc_profile->boards = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, g_free);
+ gc_profile->groups = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) gc_group_destroy);
+ gc_profile->config = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) g_hash_table_unref);
+
+ load_board("common", -1);
+
+ gint board_id = 0;
+ g_hash_table_replace(gc_profile->boards,
+ GINT_TO_POINTER(++board_id), g_strdup("menu.xml"));
+ g_hash_table_replace(gc_profile->boards,
+ GINT_TO_POINTER(++board_id), g_strdup("login.xml"));
+ load_board("login.xml", board_id);
+
+ for (i = 0; board_files[i]; i++)
+ {
+ g_hash_table_replace(gc_profile->boards,
+ GINT_TO_POINTER(++board_id), board_files[i]);
+ load_board(board_files[i], board_id);
+ }
+
+ g_free(board_files);
+
+ gchar **sections = g_key_file_get_groups(profile, NULL);
+ if (!sections)
+ return;
+
+ for (i = 0; sections[i]; i++)
+ {
+ if (!g_str_has_prefix(sections[i], "group/"))
+ continue;
+
+ GcomprisGroup *group = g_malloc0(sizeof(GcomprisGroup));
+ group->group_id = g_key_file_get_integer(profile,
+ sections[i], "group_id", NULL);
+ group->name = g_key_file_get_string(profile,
+ sections[i], "name", NULL);
+ group->class_id = g_key_file_get_integer(profile,
+ sections[i], "class_id", NULL);
+ group->description = g_key_file_get_string(profile,
+ sections[i], "description", NULL);
+
+ int *group_id = g_malloc(sizeof(int));
+ *group_id = group->group_id;
+ gc_profile->group_ids = g_list_append(gc_profile->group_ids, group_id);
+
+ g_hash_table_insert(gc_profile->groups,
+ GINT_TO_POINTER(group->group_id), group);
+
+ gchar **users = g_key_file_get_string_list(profile,
+ sections[i], "users", NULL, NULL);
+ if (users)
+ {
+ for (j = 0; users[j]; j++)
+ {
+ GcomprisUser *user = g_malloc0(sizeof(GcomprisUser));
+
+ user->user_id = g_key_file_get_integer(profile,
+ users[j], "user_id", NULL);
+ user->login = g_key_file_get_string(profile,
+ users[j], "login", NULL);
+ user->lastname = g_key_file_get_string(profile,
+ users[j], "lastname", NULL);
+ user->firstname = g_key_file_get_string(profile,
+ users[j], "firstname", NULL);
+ user->birthdate = g_key_file_get_string(profile,
+ users[j], "birthdate", NULL);
+ user->class_id = g_key_file_get_integer(profile,
+ users[j], "class_id", NULL);
+
+ group->user_ids = g_list_append(group->user_ids, user);
+ }
+ g_strfreev(users);
+ }
+ }
+ g_strfreev(sections);
+}
+
+static void
+load_board(gchar *board_file, gint board_id)
+{
+ GHashTable *config = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ g_free, g_free);
+
+ gchar *board_section = g_strdup_printf("board/%s", board_file);
+ gchar **keys = g_key_file_get_keys(profile, board_section, NULL, NULL);
+ if (keys)
+ {
+ gchar **key;
+ for (key = keys; *key; key++)
+ g_hash_table_replace(config, *key, g_strdup(g_key_file_get_string(
+ profile, board_section, *key, NULL)));
+ g_free(keys);
+ }
+ g_free(board_section);
+
+ g_hash_table_replace(gc_prop_get()->profile->config,
+ GINT_TO_POINTER(board_id), config);
+}
+
+static void
+load_profile()
+{
+ SugarJobject *jobject = sugar_activity_get_jobject(activity);
+ const char *file_path = sugar_jobject_get_file_path(jobject);
+
+ if (file_path != NULL &&
+ g_key_file_load_from_file(profile, file_path, 0, NULL))
+ setup_gc_profile();
+}
diff --git a/src/gcompris/sugar_db.c b/src/gcompris/sugar_db.c
new file mode 100644
index 0000000..79dc911
--- /dev/null
+++ b/src/gcompris/sugar_db.c
@@ -0,0 +1,479 @@
+/* gcompris - sugar_db.c
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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 <string.h>
+#include <libgen.h>
+#include <glib.h>
+#include <sqlite3.h>
+
+#include "gcompris.h"
+
+#define SQL_EXEC(result, query, ...) \
+ { \
+ int _ncolumn; \
+ char *_query = sqlite3_mprintf((query), __VA_ARGS__); \
+ db_error = NULL; \
+ result = NULL; \
+ if (sqlite3_get_table(db, _query, &result, &db_count, &_ncolumn, \
+ &db_error) != SQLITE_OK) \
+ g_warning("SQL error in '%s': %s", _query, db_error); \
+ else if (db_count == 0 || (db_count == 1 && !result[_ncolumn])) \
+ { \
+ sqlite3_free_table(result); \
+ result = NULL; \
+ } \
+ sqlite3_free(_query); \
+ } \
+ for (; result; sqlite3_free_table(result), result = NULL)
+
+static void import_classes(GKeyFile*, gchar**);
+static void import_users(GKeyFile*, gchar**);
+static void import_groups(GKeyFile*, gint);
+static void import_config(GKeyFile*, gchar*, gint, gint);
+static void import_logs(GKeyFile*, gchar**);
+
+static sqlite3 *db;
+static char *db_error;
+static int db_count;
+
+void
+sugar_db_open()
+{
+ if (sqlite3_open(gc_prop_get()->database, &db) != SQLITE_OK)
+ {
+ g_warning("Cannot open SQL db");
+ db = NULL;
+ }
+}
+
+void
+sugar_db_close(int profile_id)
+{
+ if (db == NULL)
+ return;
+
+ if (profile_id != 1)
+ {
+ char **nop;
+
+ SQL_EXEC(nop, "DELETE FROM board_profile_conf WHERE profile_id=%d;",
+ profile_id);
+ SQL_EXEC(nop, "DELETE FROM activities_out WHERE out_id=%d;", profile_id);
+ SQL_EXEC(nop, "DELETE FROM profiles WHERE profile_id=%d;", profile_id);
+ SQL_EXEC(nop, "DELETE FROM logs;", NULL);
+
+ g_debug("Cleaned up sugar profile with id %d", profile_id);
+ }
+
+ sqlite3_close(db);
+}
+
+gint
+sugar_db_write(GKeyFile *profile)
+{
+ char **result, **nop;
+ int profile_id = 1;
+ int i;
+
+ if (db == NULL)
+ return 1;
+
+ SQL_EXEC(result, "SELECT MAX(profile_id) FROM profiles;", NULL)
+ profile_id = atoi(result[1]) + 1;
+
+ SQL_EXEC(nop, "INSERT INTO profiles (profile_id, name, profile_directory,"
+ "description) VALUES (%d, %Q, %Q, %Q);",
+ profile_id, "sugar", ".", "sugar");
+ if (db_error)
+ return 1;
+
+ gchar **sections = g_key_file_get_groups(profile, NULL);
+ if (!sections)
+ return profile_id;
+
+ g_debug("Import sugar profile with id %d", profile_id);
+
+ SQL_EXEC(nop, "BEGIN TRANSACTION", NULL);
+
+ SQL_EXEC(result, "SELECT board_id, filename FROM boards;", NULL)
+ {
+ gchar **include_boards = g_key_file_get_string_list(profile,
+ "profile", "boards", NULL, NULL);
+
+ for (i = db_count + 1; i-- > 1;)
+ {
+ gboolean exclude = include_boards != NULL;
+ gchar *board_file = basename(result[i * 2 + 1]);
+ gchar **include_file;
+
+ if (include_boards)
+ for (include_file = include_boards; *include_file; include_file++)
+ if (strcmp(board_file, *include_file) == 0)
+ {
+ exclude = FALSE;
+ break;
+ }
+
+ import_config(profile, board_file, profile_id, atoi(result[i * 2]));
+
+ if (exclude)
+ SQL_EXEC(nop, "INSERT INTO activities_out (board_id, out_id) "
+ "VALUES (%s, %d);", result[i * 2], profile_id);
+ }
+ g_strfreev(include_boards);
+ }
+
+ import_config(profile, "common", profile_id, -1);
+ import_classes(profile, sections);
+ import_users(profile, sections);
+ import_groups(profile, profile_id);
+ import_logs(profile, sections);
+
+ g_strfreev(sections);
+
+ SQL_EXEC(nop, "END TRANSACTION", NULL);
+
+ return profile_id;
+}
+
+void
+sugar_db_read(GKeyFile *profile, gint profile_id)
+{
+ if (db == NULL)
+ return;
+
+ gchar **result;
+ gint i, j;
+
+ SQL_EXEC(result, "SELECT filename FROM boards "
+ "WHERE board_id NOT IN "
+ "(SELECT board_id FROM activities_out WHERE out_id=%d);",
+ profile_id)
+ {
+ gchar *files[db_count];
+ for (i = db_count + 1; i-- > 1;)
+ files[i - 1] = basename(result[i]);
+ g_key_file_set_string_list(profile, "profile", "boards",
+ (const gchar* const*)files, db_count);
+ }
+
+ SQL_EXEC(result, "SELECT boards.filename, conf_key, conf_value "
+ "FROM board_profile_conf "
+ "LEFT JOIN boards ON boards.board_id = board_profile_conf.board_id "
+ "WHERE profile_id=%d", profile_id)
+ {
+ for (i = db_count + 1; i-- > 1;)
+ {
+ gchar *board_file;
+ if (result[i * 3])
+ board_file = basename(result[i * 3]);
+ else
+ board_file = "common";
+ gchar *board_section = g_strdup_printf("board/%s", board_file);
+ g_key_file_set_string(profile, board_section,
+ result[i * 3 + 1], result[i * 3 + 2]);
+ g_free(board_section);
+ }
+ }
+
+ SQL_EXEC(result, "SELECT class_id, name, teacher FROM class "
+ "WHERE class_id IN (SELECT class_id FROM groups "
+ "WHERE group_id IN (SELECT group_id FROM list_groups_in_profiles "
+ "WHERE profile_id=%d));", profile_id)
+ {
+ for (i = db_count + 1; i-- > 1;)
+ {
+ gchar *section = g_strdup_printf("class/%s", result[i * 3 + 1]);
+ g_key_file_set_string(profile, section, "class_id", result[i * 3]);
+ g_key_file_set_string(profile, section, "name", result[i * 3 + 1]);
+ g_key_file_set_string(profile, section, "teacher", result[i * 3 + 2]);
+ g_free(section);
+ }
+ }
+
+ SQL_EXEC(result, "SELECT user_id, login, lastname, firstname, birthdate, "
+ "'class/'||class.name FROM users "
+ "INNER JOIN class ON class.class_id = users.class_id "
+ "WHERE user_id IN (SELECT user_id FROM list_users_in_groups "
+ "WHERE group_id IN (SELECT group_id FROM list_groups_in_profiles "
+ "WHERE profile_id=%d));", profile_id)
+ {
+ for (i = db_count + 1; i-- > 1;)
+ {
+ gchar *section = g_strdup_printf("user/%s", result[i * 6 + 1]);
+ g_key_file_set_string(profile, section, "user_id", result[i * 6]);
+ g_key_file_set_string(profile, section, "login", result[i * 6 + 1]);
+ g_key_file_set_string(profile, section, "lastname", result[i * 6 + 2]);
+ g_key_file_set_string(profile, section, "firstname", result[i * 6 + 3]);
+ g_key_file_set_string(profile, section, "birthdate", result[i * 6 + 4]);
+ g_key_file_set_string(profile, section, "class", result[i * 6 + 5]);
+ g_free(section);
+ }
+ }
+
+ SQL_EXEC(result, "SELECT group_id, groups.name, 'class/'||class.name, "
+ "description, 'group/'||groups.name FROM groups "
+ "INNER JOIN class ON class.class_id = groups.class_id "
+ "WHERE group_id IN (SELECT group_id FROM list_groups_in_profiles "
+ "WHERE profile_id=%d);", profile_id)
+ {
+ int group_count = db_count;
+ gchar *group_sections[group_count];
+
+ for (i = db_count + 1; i-- > 1;)
+ {
+ group_sections[i - 1] = result[i * 5 + 4];
+
+ gchar *section = g_strdup_printf("group/%s", result[i * 5 + 1]);
+ g_key_file_set_string(profile, section, "group_id", result[i * 5]);
+ g_key_file_set_string(profile, section, "name", result[i * 5 + 1]);
+ g_key_file_set_string(profile, section, "class", result[i * 5 + 2]);
+ g_key_file_set_string(profile, section, "description", result[i * 5 + 3]);
+ gchar **users_result;
+ SQL_EXEC(users_result, "SELECT 'user/'||login FROM users "
+ "WHERE user_id IN (SELECT user_id FROM list_users_in_groups "
+ "WHERE group_id=%s);", result[i * 5])
+ {
+ gchar *users[db_count];
+ for (j = db_count + 1; j-- > 1;)
+ users[j - 1] = users_result[j];
+ g_key_file_set_string_list(profile, section, "users",
+ (const gchar* const*)users, db_count);
+ }
+ g_free(section);
+ }
+
+ g_key_file_set_string_list(profile, "profile", "groups",
+ (const gchar* const*)group_sections, group_count);
+ }
+}
+
+void
+sugar_db_read_reports(GKeyFile *profile)
+{
+ if (db == NULL)
+ return;
+
+ gchar **result;
+ gint i;
+
+ SQL_EXEC(result, "SELECT date, duration, 'user/'||login, boards.name, "
+ "level, sublevel, status, comment FROM logs "
+ "LEFT JOIN users ON users.user_id = logs.user_id "
+ "INNER JOIN boards ON boards.board_id = logs.board_id;", NULL)
+ {
+ for (i = db_count + 1; i-- > 1;)
+ {
+ gchar *section = g_strdup_printf("report/%s/%s",
+ result[i * 8], result[i * 8 + 3]);
+ g_key_file_set_string(profile, section, "date", result[i * 8]);
+ g_key_file_set_string(profile, section, "duration", result[i * 8 + 1]);
+ g_key_file_set_string(profile, section, "user", result[i * 8 + 2]);
+ g_key_file_set_string(profile, section, "board", result[i * 8 + 3]);
+ g_key_file_set_string(profile, section, "level", result[i * 8 + 4]);
+ g_key_file_set_string(profile, section, "sublevel", result[i * 8 + 5]);
+ g_key_file_set_string(profile, section, "status", result[i * 8 + 6]);
+ g_key_file_set_string(profile, section, "comment", result[i * 8 + 7]);
+ g_free(section);
+ }
+ }
+}
+
+void
+sugar_db_write_report(const char *date, gint duration, const char *user,
+ const char *board, gint level, gint sublevel, gint status,
+ const char *comment)
+{
+ if (db == NULL)
+ return;
+
+ gchar **nop;
+
+ SQL_EXEC(nop, "INSERT INTO logs (date, duration, user_id, board_id, level, "
+ "sublevel, status, comment) VALUES (%Q, %d, "
+ "(select user_id from users where login=%Q), "
+ "(select board_id from boards where name=%Q), %d, %d, %d, %Q);",
+ date, duration, user, board, level, sublevel, status, comment);
+}
+
+static void
+import_classes(GKeyFile *profile, gchar **sections)
+{
+ gchar **result, **nop, **klass;
+
+ for (klass = sections; *klass; klass++)
+ {
+ if (!g_str_has_prefix(*klass, "class/"))
+ continue;
+ int klass_id = -1;
+ SQL_EXEC(result, "SELECT class_id FROM class WHERE name=%Q;",
+ g_key_file_get_string(profile, *klass, "name", NULL))
+ klass_id = atoi(result[1]);
+ if (klass_id == -1)
+ {
+ klass_id = 1;
+ SQL_EXEC(result, "SELECT MAX(class_id) FROM class;", NULL)
+ klass_id = atoi(result[1]) + 1;
+ SQL_EXEC(nop, "INSERT INTO class (class_id, name, teacher, wholegroup_id)"
+ "VALUES (%d, %Q, %Q, %d);",
+ klass_id,
+ g_key_file_get_string(profile, *klass, "name", NULL),
+ g_key_file_get_string(profile, *klass, "teacher", NULL),
+ 1);
+ if (!db_error)
+ g_debug("Imported class with id %d", klass_id);
+ }
+ g_key_file_set_integer(profile, *klass, "class_id", klass_id);
+ }
+}
+
+static void
+import_users(GKeyFile *profile, gchar **sections)
+{
+ gchar **result, **nop, **user;
+
+ for (user = sections; *user; user++)
+ {
+ if (!g_str_has_prefix(*user, "user/"))
+ continue;
+ int user_id = -1;
+ SQL_EXEC(result, "SELECT user_id FROM users WHERE login=%Q;",
+ g_key_file_get_string(profile, *user, "login", NULL))
+ user_id = atoi(result[1]);
+ if (user_id == -1)
+ {
+ user_id = 1;
+ SQL_EXEC(result, "SELECT MAX(user_id) FROM users;", NULL)
+ user_id = atoi(result[1]) + 1;
+ SQL_EXEC(nop, "INSERT INTO users (user_id, login, lastname, firstname, "
+ "birthdate, class_id) VALUES (%d, %Q, %Q, %Q, %Q, %d);",
+ user_id,
+ g_key_file_get_string(profile, *user, "login", NULL),
+ g_key_file_get_string(profile, *user, "lastname", NULL),
+ g_key_file_get_string(profile, *user, "firstname", NULL),
+ g_key_file_get_string(profile, *user, "birthdate", NULL),
+ g_key_file_get_integer(profile,
+ g_key_file_get_string(profile, *user, "class", NULL),
+ "class_id", NULL));
+ if (!db_error)
+ g_debug("Imported user with id %d", user_id);
+ }
+ g_key_file_set_integer(profile, *user, "user_id", user_id);
+ }
+}
+
+static void
+import_groups(GKeyFile *profile, gint profile_id)
+{
+ gchar **result, **nop, **group, **groups;
+
+ groups = g_key_file_get_string_list(profile, "profile", "groups", NULL, NULL);
+ if (groups == NULL)
+ return;
+
+ for (group = groups; *group; group++)
+ {
+ int group_id = -1;
+ SQL_EXEC(result, "SELECT group_id FROM groups WHERE name=%Q;",
+ g_key_file_get_string(profile, *group, "name", NULL))
+ group_id = atoi(result[1]);
+ if (group_id == -1)
+ {
+ group_id = 1;
+ SQL_EXEC(result, "SELECT MAX(group_id) FROM groups;", NULL)
+ group_id = atoi(result[1]) + 1;
+ SQL_EXEC(nop, "INSERT INTO groups (group_id, name, class_id, "
+ "description) VALUES (%d, %Q, %d, %Q);",
+ group_id,
+ g_key_file_get_string(profile, *group, "name", NULL),
+ g_key_file_get_integer(profile,
+ g_key_file_get_string(profile, *group, "class", NULL),
+ "class_id", NULL),
+ g_key_file_get_string(profile, *group, "description", NULL));
+ if (!db_error)
+ g_debug("Imported group with id %d", group_id);
+ }
+ gchar **users = g_key_file_get_string_list(profile, *group, "users",
+ NULL, NULL);
+ if (users)
+ {
+ gchar **user;
+ for (user = users; *user; user++)
+ SQL_EXEC(nop, "INSERT INTO list_users_in_groups (user_id, "
+ "group_id) VALUES (%d, %d);",
+ g_key_file_get_integer(profile, *user, "user_id", NULL),
+ group_id);
+ g_strfreev(users);
+ }
+ SQL_EXEC(nop, "INSERT INTO list_groups_in_profiles (profile_id, "
+ "group_id) VALUES (%d, %d);", profile_id, group_id);
+ g_key_file_set_integer(profile, *group, "group_id", group_id);
+ }
+
+ g_strfreev(groups);
+}
+
+static void
+import_config(GKeyFile *profile, gchar *board_file, gint profile_id,
+ gint board_id)
+{
+ gchar *board_section = g_strdup_printf("board/%s", board_file);
+ gchar **keys = g_key_file_get_keys(profile, board_section, NULL, NULL);
+ char **nop;
+
+ if (keys)
+ {
+ gchar **key;
+ for (key = keys; *key; key++)
+ SQL_EXEC(nop, "INSERT INTO board_profile_conf (profile_id, board_id, "
+ "conf_key, conf_value) VALUES (%d, %d, %Q, %Q);",
+ profile_id, board_id, *key,
+ g_key_file_get_string(profile, board_section, *key, NULL));
+ g_strfreev(keys);
+ }
+
+ g_free(board_section);
+}
+
+static void
+import_logs(GKeyFile *profile, gchar **sections)
+{
+ gchar **nop, **log;
+
+ SQL_EXEC(nop, "DELETE FROM logs;", NULL);
+
+ for (log = sections; *log; log++)
+ {
+ if (!g_str_has_prefix(*log, "report/"))
+ continue;
+
+ SQL_EXEC(nop, "INSERT INTO logs (date, duration, user_id, board_id, level, "
+ "sublevel, status, comment) VALUES (%Q, %Q, %d, "
+ "(select board_id from boards where name=%Q), %Q, %Q, %Q, %Q);",
+ g_key_file_get_string(profile, *log, "date", NULL),
+ g_key_file_get_string(profile, *log, "duration", NULL),
+ g_key_file_get_integer(profile,
+ g_key_file_get_string(profile, *log, "user", NULL),
+ "user_id", NULL),
+ g_key_file_get_string(profile, *log, "board", NULL),
+ g_key_file_get_string(profile, *log, "level", NULL),
+ g_key_file_get_string(profile, *log, "sublevel", NULL),
+ g_key_file_get_string(profile, *log, "status", NULL),
+ g_key_file_get_string(profile, *log, "comment", NULL));
+ }
+}
diff --git a/src/gcompris/sugar_db.h b/src/gcompris/sugar_db.h
new file mode 100644
index 0000000..4264bb1
--- /dev/null
+++ b/src/gcompris/sugar_db.h
@@ -0,0 +1,49 @@
+/* gcompris - sugar_db.h
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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/>.
+ */
+
+#ifndef SUGAR_DB_H
+#define SUGAR_DB_H
+
+#if defined(USE_SUGAR) && defined(USE_SQLITE)
+ void sugar_db_open(void);
+ void sugar_db_close(int profile_id);
+
+ /** Write profile data from key file to db */
+ gint sugar_db_write(GKeyFile *profile);
+
+ /** Read profile data from db and store it in key file */
+ void sugar_db_read(GKeyFile *profile, gint profile_id);
+
+ /** Write log entry to db */
+ void sugar_db_write_report (const char *date, gint duration,
+ const char *user, const char *board, gint level, gint sublevel,
+ gint status, const char *comment);
+
+ /** Read all log entries from db and store them in key file */
+ void sugar_db_read_reports (GKeyFile *profile);
+#else
+# define sugar_db_open()
+# define sugar_db_close(profile_id)
+# define sugar_db_write(config) 1
+# define sugar_db_read(config, profile_id)
+# define sugar_db_write_report(date, duration, user, board, level, sublevel, \
+ status, comment)
+# define sugar_db_read_reports(profile)
+#endif
+
+#endif
diff --git a/src/gcompris/sugar_gc.c b/src/gcompris/sugar_gc.c
new file mode 100644
index 0000000..a3ecfd6
--- /dev/null
+++ b/src/gcompris/sugar_gc.c
@@ -0,0 +1,441 @@
+/* gcompris - sugar_gc.c
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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 <sys/stat.h>
+#include <unistd.h>
+#include <gdk/gdkx.h>
+
+#include <polyol/toolkit.h>
+
+#include "gcompris.h"
+#include "gc_core.h"
+#include "bar.h"
+#include "score.h"
+#include "status.h"
+#include "sugar.h"
+
+static void bar_start(GtkContainer*, GooCanvas*);
+static void bar_set_level(GcomprisBoard*);
+static void bar_set_flags(const GComprisBarFlags);
+static void score_start(ScoreStyleList, guint, guint, guint);
+static void score_end();
+static void score_set(guint);
+static void activity_clicked_cb(GtkToolButton*, gpointer);
+static void about_clicked_cb(GtkToolButton*, gpointer);
+static void level_clicked_cb(GtkToolButton*, gpointer);
+static void refresh_clicked_cb(GtkToolButton*, gpointer);
+static void zoom_clicked_cb(GtkToolButton*, gpointer);
+static void config_clicked_cb(GtkToolButton*, gpointer);
+static void back_clicked_cb(GtkToolButton*, gpointer);
+static void stop_clicked_cb(GtkToolButton*, gpointer);
+static GtkToolItem* level_widget_new();
+static GtkToolItem* score_widget_new();
+static GtkToolItem* expander_new();
+static GtkToolItem* separator_new();
+static GtkToolItem* activity_icon_new();
+static GtkToolItem* journal_title_new();
+static GtkToolItem* share_button_new();
+
+/* export sugar bar */
+Bar sugar_bar = {
+ bar_start,
+ bar_set_level,
+ NULL,
+ NULL,
+ bar_set_flags,
+ NULL
+};
+
+/* export sugar score */
+Score sugar_score = {
+ score_start,
+ score_end,
+ score_set
+};
+
+typedef struct {
+ const gchar *icon;
+ const gchar *label;
+ gpointer cb;
+ gpointer user_data;
+} Button;
+
+static Button buttons[] = {
+ { NULL, NULL, activity_icon_new, NULL },
+ { NULL, NULL, journal_title_new, NULL },
+ { NULL, NULL, share_button_new, NULL },
+ { "stock_home", N_("About"), about_clicked_cb, NULL },
+ { "stock_refresh", N_("Refresh"), refresh_clicked_cb, NULL },
+ { "preferences-system", N_("Settings"), config_clicked_cb, NULL },
+ { "go-previous-paired", N_("Previous level"), level_clicked_cb,
+ GINT_TO_POINTER(-1) },
+ { NULL, NULL, level_widget_new, NULL },
+ { "go-next-paired", N_("Next level"), level_clicked_cb,
+ GINT_TO_POINTER(+1) },
+ { NULL, NULL, expander_new, NULL },
+ { NULL, NULL, score_widget_new, NULL },
+ { NULL, NULL, expander_new, NULL },
+ { "view-fullscreen", N_("Zoom"), zoom_clicked_cb, NULL },
+ { NULL, NULL, separator_new, NULL },
+ { "go-previous",
+ /* TRANSLATORS: Back as in previous */
+ N_("Back"), back_clicked_cb, NULL },
+ { }
+};
+
+enum {
+ BUTTON_ACTIVITY_ICON = 0,
+ BUTTON_JOURNAL_TITLE,
+ BUTTON_SHARE,
+ BUTTON_ABOUT,
+ BUTTON_REFRESH,
+ BUTTON_CONFIG,
+ BUTTON_PREV,
+ BUTTON_LEVEL,
+ BUTTON_NEXT,
+ BUTTON_EXPANDER_1,
+ BUTTON_SCORE,
+ BUTTON_EXPANDER_2,
+ BUTTON_ZOOM,
+ BUTTON_SEPARATOR,
+ BUTTON_BACK,
+ BUTTON_STOP,
+ BUTTONS_COUNT
+};
+
+static GtkToolItem *button_widgets[BUTTONS_COUNT];
+static GtkToolbar *toolbar;
+static SugarToolText *level_widget;
+static SugarToolText *score_widget;
+static gint current_level = -1;
+static gint max_score;
+
+static void
+bar_start(GtkContainer *workspace, GooCanvas *theCanvas)
+{
+ GtkToolItem *item;
+
+ SugarToolbarBox *toolbox = sugar_toolbar_box_new();
+ gtk_widget_show(GTK_WIDGET(toolbox));
+ gtk_box_pack_start(GTK_BOX(workspace), GTK_WIDGET(toolbox), FALSE, TRUE, 0);
+
+ SugarAlertBin *alerts = sugar_alert_bin_new();
+ gtk_widget_show(GTK_WIDGET(alerts));
+ gtk_box_pack_start(GTK_BOX(workspace), GTK_WIDGET(alerts), FALSE, TRUE, 0);
+
+ toolbar = GTK_TOOLBAR(sugar_toolbar_box_get_toolbar(toolbox));
+
+ item = GTK_TOOL_ITEM(sugar_stop_button_new());
+ g_signal_connect(item, "clicked", G_CALLBACK(stop_clicked_cb), NULL);
+ g_object_ref_sink(item);
+ button_widgets[BUTTON_STOP] = item;
+
+ current_level = 1;
+}
+
+static void
+set_button(gint number, gboolean visible)
+{
+ Button *button = &buttons[number];
+ GtkToolItem *item = button_widgets[number];
+
+ if (visible && item == NULL) {
+ if (button->icon == NULL)
+ item = ((GtkToolItem* (*)(void))button->cb)();
+ else {
+ SugarToolButton *tool_button = sugar_tool_button_new();
+ sugar_tool_button_set_icon_name(tool_button, button->icon);
+ sugar_tool_button_set_tooltip(tool_button, _(button->label));
+ item = GTK_TOOL_ITEM(tool_button);
+ g_signal_connect(item, "clicked", G_CALLBACK(button->cb),
+ button->user_data);
+ }
+
+ g_object_ref_sink(item);
+ button_widgets[number] = item;
+ }
+
+ if (visible) {
+ if (gtk_widget_get_parent(GTK_WIDGET(item)) == NULL) {
+ int i;
+ int item_pos = 0;
+ for (i = 0; i < number; ++i)
+ if (button_widgets[i] != NULL &&
+ gtk_widget_get_parent(GTK_WIDGET(button_widgets[i])) != NULL)
+ ++item_pos;
+
+ gtk_widget_show(GTK_WIDGET(item));
+ gtk_toolbar_insert(toolbar, item, item_pos);
+ }
+ } else if (item) {
+ if (gtk_widget_get_parent(GTK_WIDGET(item)))
+ gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(item));
+ }
+}
+
+static void
+update_level()
+{
+ gchar level_string[256];
+ snprintf(level_string, sizeof(level_string), "%d", current_level);
+ g_object_set(level_widget, "text", level_string, NULL);
+}
+
+static void
+update_score(guint value)
+{
+ gchar score_string[256];
+ snprintf(score_string, sizeof(score_string), "%d/%d", value, max_score);
+ g_object_set(score_widget, "text", score_string, NULL);
+}
+
+static GtkToolItem*
+level_widget_new()
+{
+ g_assert(level_widget == NULL);
+ level_widget = sugar_tool_text_new();
+ update_level();
+ return GTK_TOOL_ITEM(level_widget);
+}
+
+static GtkToolItem*
+score_widget_new()
+{
+ g_assert(score_widget == NULL);
+ score_widget = sugar_tool_text_new();
+ return GTK_TOOL_ITEM(score_widget);
+}
+
+static GtkToolItem*
+separator_new()
+{
+ GtkToolItem *separator = gtk_separator_tool_item_new();
+ gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(separator), FALSE);
+ return separator;
+}
+
+static GtkToolItem*
+expander_new()
+{
+ GtkToolItem *expander = gtk_separator_tool_item_new();
+ gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(expander), FALSE);
+ gtk_tool_item_set_expand(GTK_TOOL_ITEM(expander), TRUE);
+ return expander;
+}
+
+static void
+beep()
+{
+ gc_sound_play_ogg("sounds/bleep.wav", NULL);
+}
+
+static void
+activity_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+ GcomprisBoard *board = gc_board_get_current();
+ if (gc_help_has_board(board))
+ gc_help_start(board);
+}
+
+static void
+level_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+
+ GcomprisBoard *board = gc_board_get_current();
+ if (board == NULL)
+ return;
+
+ gint delta = GPOINTER_TO_INT(user_data);
+ current_level += delta;
+
+ if (current_level > board->maxlevel)
+ current_level = 1;
+ else if (current_level < 1)
+ current_level = board->maxlevel;
+
+ update_level();
+
+ if (board->plugin->set_level != NULL)
+ board->plugin->set_level(current_level);
+
+ gc_bar_play_level_voice(current_level);
+}
+
+static void
+refresh_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+ GcomprisBoard *board = gc_board_get_current();
+ if(board && board->plugin->repeat != NULL)
+ board->plugin->repeat();
+}
+
+static void
+zoom_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+ GcomprisProperties *properties = gc_prop_get();
+ properties->zoom = (properties->zoom ? 0 : 1);
+ gc_update_canvas_zoom();
+}
+
+static void
+config_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+ GcomprisBoard *board = gc_board_get_current();
+ if(board && board->plugin->config_start != NULL)
+ board->plugin->config_start(board, gc_profile_get_current());
+}
+
+static void
+back_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ gc_board_stop();
+}
+
+static void
+stop_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ // save zoom setting
+ GcomprisProperties *properties = gc_prop_get();
+ gc_prop_save(properties);
+
+ gc_exit();
+}
+
+static void
+bar_set_flags(const GComprisBarFlags flags)
+{
+ GcomprisBoard *board = gc_board_get_current();
+ gboolean sub_activity = board && board->previous_board;
+
+ if (switch_board_jobject() && flags & GC_BAR_JOURNAL)
+ {
+ set_button(BUTTON_JOURNAL_TITLE, FALSE);
+ if (button_widgets[BUTTON_JOURNAL_TITLE])
+ g_object_unref(G_OBJECT(button_widgets[BUTTON_JOURNAL_TITLE]));
+ button_widgets[BUTTON_JOURNAL_TITLE] = NULL;
+ }
+
+ set_button(BUTTON_ACTIVITY_ICON, FALSE);
+ if (button_widgets[BUTTON_ACTIVITY_ICON])
+ g_object_unref(G_OBJECT(button_widgets[BUTTON_ACTIVITY_ICON]));
+ button_widgets[BUTTON_ACTIVITY_ICON] = NULL;
+
+ set_button(BUTTON_ACTIVITY_ICON, TRUE);
+ set_button(BUTTON_JOURNAL_TITLE, flags & GC_BAR_JOURNAL);
+ set_button(BUTTON_SHARE, sugar_activity_get_connection(activity) != NULL &&
+ flags & GC_BAR_SHARE);
+ set_button(BUTTON_ABOUT, flags & GC_BAR_ABOUT);
+
+ set_button(BUTTON_PREV, flags & GC_BAR_LEVEL);
+ set_button(BUTTON_LEVEL, flags & GC_BAR_LEVEL);
+ set_button(BUTTON_NEXT, flags & GC_BAR_LEVEL);
+
+ set_button(BUTTON_REFRESH, flags & (GC_BAR_REPEAT | GC_BAR_REPEAT_ICON));
+ set_button(BUTTON_CONFIG, flags & GC_BAR_CONFIG);
+
+ set_button(BUTTON_EXPANDER_1, TRUE);
+ set_button(BUTTON_SCORE, max_score);
+ set_button(BUTTON_EXPANDER_2, TRUE);
+
+ set_button(BUTTON_ZOOM, strcmp("/", gc_prop_get()->root_menu) != 0 &&
+ strcmp("/login/login", gc_prop_get()->root_menu) != 0);
+ set_button(BUTTON_SEPARATOR, TRUE);
+
+ set_button(BUTTON_BACK, sub_activity);
+ set_button(BUTTON_STOP, !sub_activity);
+}
+
+static void
+score_start(ScoreStyleList style, guint x, guint y, guint max)
+{
+ max_score = max;
+ set_button(BUTTON_SCORE, TRUE);
+ update_score(0);
+}
+
+static void
+score_end()
+{
+ max_score = 0;
+ set_button(BUTTON_SCORE, FALSE);
+}
+
+static void
+score_set(guint value)
+{
+ update_score(value);
+}
+
+static void
+bar_set_level(GcomprisBoard *board)
+{
+ if (board == NULL)
+ return;
+
+ if (level_widget == NULL) {
+ g_message("in bar_set_level, level_widget == NULL should not happen\n");
+ return;
+ }
+
+ current_level = board->level;
+ update_level();
+}
+
+static GtkToolItem*
+activity_icon_new()
+{
+ SugarActivityButton *item = sugar_activity_button_new(board_jobject);
+ if (is_activity_board())
+ {
+ gchar *icon_file = g_strdup_printf("%s/%s",
+ gc_prop_get()->menu_dir, gc_board_get_current()->icon_name);
+ sugar_tool_button_set_icon_name(SUGAR_TOOL_BUTTON(item), icon_file);
+ g_free(icon_file);
+ }
+ g_signal_connect(item, "clicked", G_CALLBACK(activity_clicked_cb), NULL);
+ return GTK_TOOL_ITEM(item);
+}
+
+static GtkToolItem*
+journal_title_new()
+{
+ GtkToolItem *item;
+ item = GTK_TOOL_ITEM(sugar_title_entry_new(board_jobject));
+ return item;
+}
+
+static GtkToolItem*
+share_button_new()
+{
+ GtkToolItem *item;
+ SugarConnection *connection = sugar_activity_get_connection(activity);
+ item = GTK_TOOL_ITEM(sugar_share_button_new(connection));
+ return item;
+}
+
+static void
+about_clicked_cb(GtkToolButton *button, gpointer user_data)
+{
+ beep();
+ gc_about_start();
+}
diff --git a/src/gcompris/sugar_gc.h b/src/gcompris/sugar_gc.h
new file mode 100644
index 0000000..36071f5
--- /dev/null
+++ b/src/gcompris/sugar_gc.h
@@ -0,0 +1,79 @@
+/* gcompris - sugar.h
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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/>.
+ */
+
+#ifndef SUGAR_GC_H
+#define SUGAR_GC_H
+
+#ifdef USE_SUGAR
+ /** Initialize sugar libraries */
+ void sugar_setup(int *argc, char ***argv);
+
+ /** Was sugar mode detected on startup */
+ gboolean sugar_detected(void);
+
+ /** If sugar object restred from Journal, root menu to launch */
+ const gchar *sugar_jobject_root_menu(void);
+
+ /** Start is delayed until sugar retreaves remote data */
+ gboolean sugar_delayed_start(void);
+
+ /** Load sugar profile */
+ void sugar_setup_profile(const gchar *root, gboolean administration);
+
+ /** Setup X11 properties for main GC window */
+ void sugar_setup_x11();
+
+ /** Cleanup sugar related data */
+ void sugar_cleanup(void);
+
+ /** Get filename from current journal object */
+ const char *sugar_load(void);
+
+ /** Save file to current journal object */
+ void sugar_save(const char *path);
+
+ /** Start image chooser sugar dialog */
+ void sugar_choose_image(ImageSelectorCallBack iscb, void *user_context);
+
+ /** Get journal file by id previously returned by sugar_choose_image */
+ gchar *sugar_get_journal_file(gchar *file_id);
+
+ /** Get profile id imported to db from journal object */
+ gint sugar_get_profile_id(void);
+
+ /** Register a log report within sugar */
+ void sugar_report(const gchar *date, guint duration, const gchar *user,
+ GcomprisBoard *board, GCBonusStatusList status,
+ const gchar *comment);
+#else
+# define sugar_setup(argc, argv)
+# define sugar_detected() FALSE
+# define sugar_jobject_root_menu() FALSE
+# define sugar_delayed_start() FALSE
+# define sugar_setup_profile(root, administration)
+# define sugar_setup_x11()
+# define sugar_cleanup()
+# define sugar_load() NULL
+# define sugar_save(path)
+# define sugar_choose_image(iscb, user_context)
+# define sugar_get_journal_file(file_id) (file_id)
+# define sugar_get_profile_id() 1
+# define sugar_report(date, duration, user, board, status, comment)
+#endif
+
+#endif
diff --git a/src/gcompris/sugar_share.c b/src/gcompris/sugar_share.c
new file mode 100644
index 0000000..8e14a29
--- /dev/null
+++ b/src/gcompris/sugar_share.c
@@ -0,0 +1,977 @@
+/* sugar_share.c generated by valac, the Vala compiler
+ * generated from sugar_share.vala, do not modify */
+
+/* gcompris - sugar_share.vala
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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 <glib.h>
+#include <glib-object.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sugar_share.h"
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+#include <gobject/gvaluecollector.h>
+#include <dbus/dbus.h>
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL)))
+#define _dbus_g_connection_unref0(var) ((var == NULL) ? NULL : (var = (dbus_g_connection_unref (var), NULL)))
+#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
+typedef struct _ParamSpecAdministrationClient ParamSpecAdministrationClient;
+typedef struct _ParamSpecAdministrationServer ParamSpecAdministrationServer;
+typedef struct _DBusObjectVTable _DBusObjectVTable;
+
+struct _AdministrationPrivate {
+ GetProfileCallback _GetProfile_cb;
+ gpointer _GetProfile_cb_target;
+ GDestroyNotify _GetProfile_cb_target_destroy_notify;
+ ReportCallback _Report_cb;
+ gpointer _Report_cb_target;
+ GDestroyNotify _Report_cb_target_destroy_notify;
+};
+
+struct _AdministrationClientPrivate {
+ DBusGProxy* _server;
+ DBusGConnection* _connection;
+ GotProfileCallback _GotProfile_cb;
+ gpointer _GotProfile_cb_target;
+ GDestroyNotify _GotProfile_cb_target_destroy_notify;
+};
+
+struct _ParamSpecAdministrationClient {
+ GParamSpec parent_instance;
+};
+
+struct _AdministrationServerPrivate {
+ Administration* _server;
+ DBusGConnection* _connection;
+};
+
+struct _ParamSpecAdministrationServer {
+ GParamSpec parent_instance;
+};
+
+struct _DBusObjectVTable {
+ void (*register_object) (DBusConnection*, const char*, void*);
+};
+
+
+static gpointer administration_parent_class = NULL;
+static gpointer administration_client_parent_class = NULL;
+static gpointer administration_server_parent_class = NULL;
+
+#define _PATH "/org/gcompris/Administration"
+#define _IFACE "org.gcompris.Administration"
+#define ADMINISTRATION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ADMINISTRATION, AdministrationPrivate))
+enum {
+ ADMINISTRATION_DUMMY_PROPERTY
+};
+void administration_dbus_register_object (DBusConnection* connection, const char* path, void* object);
+void _administration_dbus_unregister (DBusConnection* connection, void* _user_data_);
+DBusHandlerResult administration_dbus_message (DBusConnection* connection, DBusMessage* message, void* object);
+static DBusHandlerResult _dbus_administration_introspect (Administration* self, DBusConnection* connection, DBusMessage* message);
+static DBusHandlerResult _dbus_administration_property_get_all (Administration* self, DBusConnection* connection, DBusMessage* message);
+static DBusHandlerResult _dbus_administration_GetProfile (Administration* self, DBusConnection* connection, DBusMessage* message);
+static DBusHandlerResult _dbus_administration_Report (Administration* self, DBusConnection* connection, DBusMessage* message);
+static void _dbus_administration_update_profile (GObject* _sender, DBusConnection* _connection);
+static void administration_finalize (GObject* obj);
+#define ADMINISTRATION_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ADMINISTRATION_CLIENT, AdministrationClientPrivate))
+enum {
+ ADMINISTRATION_CLIENT_DUMMY_PROPERTY
+};
+static void _administration_client_UpdateProfile_cb (AdministrationClient* self, DBusGProxy* sender);
+static void __administration_client_UpdateProfile_cb_dynamic_UpdateProfile_ (DBusGProxy* _sender, gpointer self);
+void _dynamic_UpdateProfile_conect (gpointer obj, const char * signal_name, GCallback handler, gpointer data);
+static void _administration_client_GetProfile_cb (AdministrationClient* self, const char* profile_data, GError* _error_);
+static void _dynamic_GetProfile0 (DBusGProxy* self, gpointer param1, void* param1_target, GError** error);
+static void _administration_client_Report_cb (AdministrationClient* self, GError* _error_);
+static void _dynamic_Report1 (DBusGProxy* self, const char* param1, gint param2, const char* param3, const char* param4, gint param5, gint param6, gint param7, const char* param8, gpointer param9, void* param9_target, GError** error);
+static void administration_client_finalize (AdministrationClient* obj);
+#define ADMINISTRATION_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_ADMINISTRATION_SERVER, AdministrationServerPrivate))
+enum {
+ ADMINISTRATION_SERVER_DUMMY_PROPERTY
+};
+static void administration_server_finalize (AdministrationServer* obj);
+static void _vala_dbus_register_object (DBusConnection* connection, const char* path, void* object);
+static void _vala_dbus_unregister_object (gpointer connection, GObject* object);
+
+static const DBusObjectPathVTable _administration_dbus_path_vtable = {_administration_dbus_unregister, administration_dbus_message};
+static const _DBusObjectVTable _administration_dbus_vtable = {administration_dbus_register_object};
+
+
+Administration* administration_construct (GType object_type, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target) {
+ Administration * self;
+ GetProfileCallback _tmp0_;
+ ReportCallback _tmp1_;
+ self = (Administration*) g_object_new (object_type, NULL);
+ self->priv->_GetProfile_cb = (_tmp0_ = GetProfile_cb, ((self->priv->_GetProfile_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_GetProfile_cb_target_destroy_notify (self->priv->_GetProfile_cb_target), NULL), self->priv->_GetProfile_cb = NULL, self->priv->_GetProfile_cb_target = NULL, self->priv->_GetProfile_cb_target_destroy_notify = NULL), self->priv->_GetProfile_cb_target = GetProfile_cb_target, self->priv->_GetProfile_cb_target_destroy_notify = NULL, _tmp0_);
+ self->priv->_Report_cb = (_tmp1_ = Report_cb, ((self->priv->_Report_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_Report_cb_target_destroy_notify (self->priv->_Report_cb_target), NULL), self->priv->_Report_cb = NULL, self->priv->_Report_cb_target = NULL, self->priv->_Report_cb_target_destroy_notify = NULL), self->priv->_Report_cb_target = Report_cb_target, self->priv->_Report_cb_target_destroy_notify = NULL, _tmp1_);
+ return self;
+}
+
+
+Administration* administration_new (GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target) {
+ return administration_construct (TYPE_ADMINISTRATION, GetProfile_cb, GetProfile_cb_target, Report_cb, Report_cb_target);
+}
+
+
+char* administration_GetProfile (Administration* self) {
+ char* result = NULL;
+ g_return_val_if_fail (self != NULL, NULL);
+ g_debug ("sugar_share.vala:53: GetProfile called on server");
+ result = self->priv->_GetProfile_cb (self->priv->_GetProfile_cb_target);
+ return result;
+}
+
+
+void administration_Report (Administration* self, const char* date, gint duration, const char* user, const char* board, gint level, gint sublevel, gint status, const char* comment) {
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (date != NULL);
+ g_return_if_fail (user != NULL);
+ g_return_if_fail (board != NULL);
+ g_return_if_fail (comment != NULL);
+ g_debug ("sugar_share.vala:62: Report called on server");
+ self->priv->_Report_cb (date, duration, user, board, level, sublevel, status, comment, self->priv->_Report_cb_target);
+}
+
+
+void _administration_dbus_unregister (DBusConnection* connection, void* _user_data_) {
+}
+
+
+static DBusHandlerResult _dbus_administration_introspect (Administration* self, DBusConnection* connection, DBusMessage* message) {
+ DBusMessage* reply;
+ DBusMessageIter iter;
+ GString* xml_data;
+ char** children;
+ int i;
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ xml_data = g_string_new ("<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n");
+ g_string_append (xml_data, "<node>\n<interface name=\"org.freedesktop.DBus.Introspectable\">\n <method name=\"Introspect\">\n <arg name=\"data\" direction=\"out\" type=\"s\"/>\n </method>\n</interface>\n<interface name=\"org.freedesktop.DBus.Properties\">\n <method name=\"Get\">\n <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n <arg name=\"propname\" direction=\"in\" type=\"s\"/>\n <arg name=\"value\" direction=\"out\" type=\"v\"/>\n </method>\n <method name=\"Set\">\n <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n <arg name=\"propname\" direction=\"in\" type=\"s\"/>\n <arg name=\"value\" direction=\"in\" type=\"v\"/>\n </method>\n <method name=\"GetAll\">\n <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n <arg name=\"props\" direction=\"out\" type=\"a{sv}\"/>\n </method>\n</interface>\n<interface name=\"org.gcompris.Administration\">\n <method name=\"GetProfile\">\n <arg name=\"result\" type=\"s\" direction=\"o
ut\"/>\n </method>\n <method name=\"Report\">\n <arg name=\"date\" type=\"s\" direction=\"in\"/>\n <arg name=\"duration\" type=\"i\" direction=\"in\"/>\n <arg name=\"user\" type=\"s\" direction=\"in\"/>\n <arg name=\"board\" type=\"s\" direction=\"in\"/>\n <arg name=\"level\" type=\"i\" direction=\"in\"/>\n <arg name=\"sublevel\" type=\"i\" direction=\"in\"/>\n <arg name=\"status\" type=\"i\" direction=\"in\"/>\n <arg name=\"comment\" type=\"s\" direction=\"in\"/>\n </method>\n <signal name=\"UpdateProfile\">\n </signal>\n</interface>\n");
+ dbus_connection_list_registered (connection, g_object_get_data ((GObject *) self, "dbus_object_path"), &children);
+ for (i = 0; children[i]; i++) {
+ g_string_append_printf (xml_data, "<node name=\"%s\"/>\n", children[i]);
+ }
+ dbus_free_string_array (children);
+ g_string_append (xml_data, "</node>\n");
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &xml_data->str);
+ g_string_free (xml_data, TRUE);
+ if (reply) {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+
+static DBusHandlerResult _dbus_administration_property_get_all (Administration* self, DBusConnection* connection, DBusMessage* message) {
+ DBusMessage* reply;
+ DBusMessageIter iter, reply_iter, subiter;
+ char* interface_name;
+ const char* _tmp0_;
+ if (strcmp (dbus_message_get_signature (message), "s")) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_iter_init (message, &iter);
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &reply_iter);
+ dbus_message_iter_get_basic (&iter, &_tmp0_);
+ dbus_message_iter_next (&iter);
+ interface_name = g_strdup (_tmp0_);
+ if (strcmp (interface_name, "org.gcompris.Administration") == 0) {
+ dbus_message_iter_open_container (&reply_iter, DBUS_TYPE_ARRAY, "{sv}", &subiter);
+ dbus_message_iter_close_container (&reply_iter, &subiter);
+ } else {
+ dbus_message_unref (reply);
+ reply = NULL;
+ }
+ g_free (interface_name);
+ if (reply) {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+
+static DBusHandlerResult _dbus_administration_GetProfile (Administration* self, DBusConnection* connection, DBusMessage* message) {
+ DBusMessageIter iter;
+ GError* error;
+ char* result;
+ DBusMessage* reply;
+ const char* _tmp1_;
+ error = NULL;
+ if (strcmp (dbus_message_get_signature (message), "")) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_iter_init (message, &iter);
+ result = administration_GetProfile (self);
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ _tmp1_ = result;
+ dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &_tmp1_);
+ _g_free0 (result);
+ if (reply) {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+
+static DBusHandlerResult _dbus_administration_Report (Administration* self, DBusConnection* connection, DBusMessage* message) {
+ DBusMessageIter iter;
+ GError* error;
+ char* date = NULL;
+ const char* _tmp2_;
+ gint duration = 0;
+ dbus_int32_t _tmp3_;
+ char* user = NULL;
+ const char* _tmp4_;
+ char* board = NULL;
+ const char* _tmp5_;
+ gint level = 0;
+ dbus_int32_t _tmp6_;
+ gint sublevel = 0;
+ dbus_int32_t _tmp7_;
+ gint status = 0;
+ dbus_int32_t _tmp8_;
+ char* comment = NULL;
+ const char* _tmp9_;
+ DBusMessage* reply;
+ error = NULL;
+ if (strcmp (dbus_message_get_signature (message), "sissiiis")) {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ dbus_message_iter_init (message, &iter);
+ dbus_message_iter_get_basic (&iter, &_tmp2_);
+ dbus_message_iter_next (&iter);
+ date = g_strdup (_tmp2_);
+ dbus_message_iter_get_basic (&iter, &_tmp3_);
+ dbus_message_iter_next (&iter);
+ duration = _tmp3_;
+ dbus_message_iter_get_basic (&iter, &_tmp4_);
+ dbus_message_iter_next (&iter);
+ user = g_strdup (_tmp4_);
+ dbus_message_iter_get_basic (&iter, &_tmp5_);
+ dbus_message_iter_next (&iter);
+ board = g_strdup (_tmp5_);
+ dbus_message_iter_get_basic (&iter, &_tmp6_);
+ dbus_message_iter_next (&iter);
+ level = _tmp6_;
+ dbus_message_iter_get_basic (&iter, &_tmp7_);
+ dbus_message_iter_next (&iter);
+ sublevel = _tmp7_;
+ dbus_message_iter_get_basic (&iter, &_tmp8_);
+ dbus_message_iter_next (&iter);
+ status = _tmp8_;
+ dbus_message_iter_get_basic (&iter, &_tmp9_);
+ dbus_message_iter_next (&iter);
+ comment = g_strdup (_tmp9_);
+ administration_Report (self, date, duration, user, board, level, sublevel, status, comment);
+ reply = dbus_message_new_method_return (message);
+ dbus_message_iter_init_append (reply, &iter);
+ _g_free0 (date);
+ _g_free0 (user);
+ _g_free0 (board);
+ _g_free0 (comment);
+ if (reply) {
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+
+DBusHandlerResult administration_dbus_message (DBusConnection* connection, DBusMessage* message, void* object) {
+ DBusHandlerResult result;
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
+ result = _dbus_administration_introspect (object, connection, message);
+ } else if (dbus_message_is_method_call (message, "org.freedesktop.DBus.Properties", "GetAll")) {
+ result = _dbus_administration_property_get_all (object, connection, message);
+ } else if (dbus_message_is_method_call (message, "org.gcompris.Administration", "GetProfile")) {
+ result = _dbus_administration_GetProfile (object, connection, message);
+ } else if (dbus_message_is_method_call (message, "org.gcompris.Administration", "Report")) {
+ result = _dbus_administration_Report (object, connection, message);
+ }
+ if (result == DBUS_HANDLER_RESULT_HANDLED) {
+ return result;
+ } else {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+}
+
+
+static void _dbus_administration_update_profile (GObject* _sender, DBusConnection* _connection) {
+ const char * _path;
+ DBusMessage *_message;
+ DBusMessageIter _iter;
+ _path = g_object_get_data (_sender, "dbus_object_path");
+ _message = dbus_message_new_signal (_path, "org.gcompris.Administration", "UpdateProfile");
+ dbus_message_iter_init_append (_message, &_iter);
+ dbus_connection_send (_connection, _message, NULL);
+ dbus_message_unref (_message);
+}
+
+
+void administration_dbus_register_object (DBusConnection* connection, const char* path, void* object) {
+ if (!g_object_get_data (object, "dbus_object_path")) {
+ g_object_set_data (object, "dbus_object_path", g_strdup (path));
+ dbus_connection_register_object_path (connection, path, &_administration_dbus_path_vtable, object);
+ g_object_weak_ref (object, _vala_dbus_unregister_object, connection);
+ }
+ g_signal_connect (object, "update-profile", (GCallback) _dbus_administration_update_profile, connection);
+}
+
+
+static void administration_class_init (AdministrationClass * klass) {
+ administration_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (AdministrationPrivate));
+ G_OBJECT_CLASS (klass)->finalize = administration_finalize;
+ g_signal_new ("update_profile", TYPE_ADMINISTRATION, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+ g_type_set_qdata (TYPE_ADMINISTRATION, g_quark_from_static_string ("DBusObjectVTable"), (void*) (&_administration_dbus_vtable));
+}
+
+
+static void administration_instance_init (Administration * self) {
+ self->priv = ADMINISTRATION_GET_PRIVATE (self);
+}
+
+
+static void administration_finalize (GObject* obj) {
+ Administration * self;
+ self = ADMINISTRATION (obj);
+ (self->priv->_GetProfile_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_GetProfile_cb_target_destroy_notify (self->priv->_GetProfile_cb_target), NULL);
+ self->priv->_GetProfile_cb = NULL;
+ self->priv->_GetProfile_cb_target = NULL;
+ self->priv->_GetProfile_cb_target_destroy_notify = NULL;
+ (self->priv->_Report_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_Report_cb_target_destroy_notify (self->priv->_Report_cb_target), NULL);
+ self->priv->_Report_cb = NULL;
+ self->priv->_Report_cb_target = NULL;
+ self->priv->_Report_cb_target_destroy_notify = NULL;
+ G_OBJECT_CLASS (administration_parent_class)->finalize (obj);
+}
+
+
+GType administration_get_type (void) {
+ static volatile gsize administration_type_id__volatile = 0;
+ if (g_once_init_enter (&administration_type_id__volatile)) {
+ static const GTypeInfo g_define_type_info = { sizeof (AdministrationClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) administration_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Administration), 0, (GInstanceInitFunc) administration_instance_init, NULL };
+ GType administration_type_id;
+ administration_type_id = g_type_register_static (G_TYPE_OBJECT, "Administration", &g_define_type_info, 0);
+ g_once_init_leave (&administration_type_id__volatile, administration_type_id);
+ }
+ return administration_type_id__volatile;
+}
+
+
+static void __administration_client_UpdateProfile_cb_dynamic_UpdateProfile_ (DBusGProxy* _sender, gpointer self) {
+ _administration_client_UpdateProfile_cb (self, _sender);
+}
+
+
+void _dynamic_UpdateProfile_conect (gpointer obj, const char * signal_name, GCallback handler, gpointer data) {
+ dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (obj, "UpdateProfile", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal (obj, signal_name, handler, data, NULL);
+}
+
+
+AdministrationClient* administration_client_construct (GType object_type, const char* address, const char* name, GotProfileCallback GotProfile_cb, void* GotProfile_cb_target) {
+ GError * _inner_error_;
+ AdministrationClient* self;
+ GotProfileCallback _tmp0_;
+ DBusGProxy* _tmp3_;
+ g_return_val_if_fail (address != NULL, NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+ _inner_error_ = NULL;
+ self = (AdministrationClient*) g_type_create_instance (object_type);
+ self->priv->_GotProfile_cb = (_tmp0_ = GotProfile_cb, ((self->priv->_GotProfile_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_GotProfile_cb_target_destroy_notify (self->priv->_GotProfile_cb_target), NULL), self->priv->_GotProfile_cb = NULL, self->priv->_GotProfile_cb_target = NULL, self->priv->_GotProfile_cb_target_destroy_notify = NULL), self->priv->_GotProfile_cb_target = GotProfile_cb_target, self->priv->_GotProfile_cb_target_destroy_notify = NULL, _tmp0_);
+ {
+ DBusGConnection* _tmp1_;
+ DBusGConnection* _tmp2_;
+ _tmp1_ = dbus_g_connection_open (address, &_inner_error_);
+ if (_inner_error_ != NULL) {
+ goto __catch0_g_error;
+ }
+ self->priv->_connection = (_tmp2_ = _tmp1_, _dbus_g_connection_unref0 (self->priv->_connection), _tmp2_);
+ }
+ goto __finally0;
+ __catch0_g_error:
+ {
+ GError * _error_;
+ _error_ = _inner_error_;
+ _inner_error_ = NULL;
+ {
+ g_warning ("sugar_share.vala:88: Cannot open DBus connection: %s", _error_->message);
+ _g_error_free0 (_error_);
+ return self;
+ }
+ }
+ __finally0:
+ if (_inner_error_ != NULL) {
+ g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+ g_clear_error (&_inner_error_);
+ return NULL;
+ }
+ self->priv->_server = (_tmp3_ = dbus_g_proxy_new_for_name (self->priv->_connection, name, _PATH, _IFACE), _g_object_unref0 (self->priv->_server), _tmp3_);
+ _dynamic_UpdateProfile_conect (self->priv->_server, "UpdateProfile", (GCallback) __administration_client_UpdateProfile_cb_dynamic_UpdateProfile_, self);
+ return self;
+}
+
+
+AdministrationClient* administration_client_new (const char* address, const char* name, GotProfileCallback GotProfile_cb, void* GotProfile_cb_target) {
+ return administration_client_construct (TYPE_ADMINISTRATION_CLIENT, address, name, GotProfile_cb, GotProfile_cb_target);
+}
+
+
+static void __administration_client_GetProfile_cb_cb (DBusGProxy* proxy, DBusGProxyCall* call, void* user_data) {
+ GError* error;
+ const char* profile_data;
+ error = NULL;
+ dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING, &profile_data, G_TYPE_INVALID);
+ _administration_client_GetProfile_cb (user_data, profile_data, error);
+ administration_client_unref (user_data);
+}
+
+
+static void _dynamic_GetProfile0 (DBusGProxy* self, gpointer param1, void* param1_target, GError** error) {
+ dbus_g_proxy_begin_call (self, "GetProfile", __administration_client_GetProfile_cb_cb, administration_client_ref (param1_target), NULL, G_TYPE_INVALID, G_TYPE_INVALID);
+ if (*error) {
+ return;
+ }
+}
+
+
+void administration_client_import_profile (AdministrationClient* self) {
+ GError * _inner_error_;
+ g_return_if_fail (self != NULL);
+ _inner_error_ = NULL;
+ if (self->priv->_server == NULL) {
+ return;
+ }
+ g_debug ("sugar_share.vala:103: GetProfile called on client");
+ {
+ _dynamic_GetProfile0 (self->priv->_server, _administration_client_GetProfile_cb, self, &_inner_error_);
+ if (_inner_error_ != NULL) {
+ goto __catch1_g_error;
+ }
+ }
+ goto __finally1;
+ __catch1_g_error:
+ {
+ GError * _error_;
+ _error_ = _inner_error_;
+ _inner_error_ = NULL;
+ {
+ g_warning ("sugar_share.vala:108: Cannot get server profile: %s", _error_->message);
+ self->priv->_GotProfile_cb (NULL, self->priv->_GotProfile_cb_target);
+ _g_error_free0 (_error_);
+ }
+ }
+ __finally1:
+ if (_inner_error_ != NULL) {
+ g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+ g_clear_error (&_inner_error_);
+ return;
+ }
+}
+
+
+static void __administration_client_Report_cb_cb (DBusGProxy* proxy, DBusGProxyCall* call, void* user_data) {
+ GError* error;
+ error = NULL;
+ dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+ _administration_client_Report_cb (user_data, error);
+ administration_client_unref (user_data);
+}
+
+
+static void _dynamic_Report1 (DBusGProxy* self, const char* param1, gint param2, const char* param3, const char* param4, gint param5, gint param6, gint param7, const char* param8, gpointer param9, void* param9_target, GError** error) {
+ dbus_g_proxy_begin_call (self, "Report", __administration_client_Report_cb_cb, administration_client_ref (param9_target), NULL, G_TYPE_STRING, param1, G_TYPE_INT, param2, G_TYPE_STRING, param3, G_TYPE_STRING, param4, G_TYPE_INT, param5, G_TYPE_INT, param6, G_TYPE_INT, param7, G_TYPE_STRING, param8, G_TYPE_INVALID, G_TYPE_INVALID);
+ if (*error) {
+ return;
+ }
+}
+
+
+void administration_client_report (AdministrationClient* self, const char* date, gint duration, const char* user, const char* board, gint level, gint sublevel, gint status, const char* comment) {
+ GError * _inner_error_;
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (date != NULL);
+ g_return_if_fail (user != NULL);
+ g_return_if_fail (board != NULL);
+ g_return_if_fail (comment != NULL);
+ _inner_error_ = NULL;
+ if (self->priv->_server == NULL) {
+ return;
+ }
+ g_debug ("sugar_share.vala:121: Send report");
+ _dynamic_Report1 (self->priv->_server, date, duration, user, board, level, sublevel, status, comment, _administration_client_Report_cb, self, &_inner_error_);
+ if (_inner_error_ != NULL) {
+ g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+ g_clear_error (&_inner_error_);
+ return;
+ }
+}
+
+
+static void _administration_client_Report_cb (AdministrationClient* self, GError* _error_) {
+ g_return_if_fail (self != NULL);
+ if (_error_ != NULL) {
+ g_warning ("sugar_share.vala:129: Cannot send report to server: %s", _error_->message);
+ }
+}
+
+
+static void _administration_client_GetProfile_cb (AdministrationClient* self, const char* profile_data, GError* _error_) {
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (profile_data != NULL);
+ if (_error_ != NULL) {
+ g_warning ("sugar_share.vala:135: Cannot get server profile: %s", _error_->message);
+ self->priv->_GotProfile_cb (NULL, self->priv->_GotProfile_cb_target);
+ } else {
+ self->priv->_GotProfile_cb (profile_data, self->priv->_GotProfile_cb_target);
+ }
+}
+
+
+static void _administration_client_UpdateProfile_cb (AdministrationClient* self, DBusGProxy* sender) {
+ g_return_if_fail (self != NULL);
+ g_return_if_fail (sender != NULL);
+ administration_client_import_profile (self);
+}
+
+
+static void value_administration_client_init (GValue* value) {
+ value->data[0].v_pointer = NULL;
+}
+
+
+static void value_administration_client_free_value (GValue* value) {
+ if (value->data[0].v_pointer) {
+ administration_client_unref (value->data[0].v_pointer);
+ }
+}
+
+
+static void value_administration_client_copy_value (const GValue* src_value, GValue* dest_value) {
+ if (src_value->data[0].v_pointer) {
+ dest_value->data[0].v_pointer = administration_client_ref (src_value->data[0].v_pointer);
+ } else {
+ dest_value->data[0].v_pointer = NULL;
+ }
+}
+
+
+static gpointer value_administration_client_peek_pointer (const GValue* value) {
+ return value->data[0].v_pointer;
+}
+
+
+static gchar* value_administration_client_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
+ if (collect_values[0].v_pointer) {
+ AdministrationClient* object;
+ object = collect_values[0].v_pointer;
+ if (object->parent_instance.g_class == NULL) {
+ return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
+ } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
+ return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
+ }
+ value->data[0].v_pointer = administration_client_ref (object);
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ return NULL;
+}
+
+
+static gchar* value_administration_client_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
+ AdministrationClient** object_p;
+ object_p = collect_values[0].v_pointer;
+ if (!object_p) {
+ return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+ }
+ if (!value->data[0].v_pointer) {
+ *object_p = NULL;
+ } else if (collect_flags && G_VALUE_NOCOPY_CONTENTS) {
+ *object_p = value->data[0].v_pointer;
+ } else {
+ *object_p = administration_client_ref (value->data[0].v_pointer);
+ }
+ return NULL;
+}
+
+
+GParamSpec* param_spec_administration_client (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) {
+ ParamSpecAdministrationClient* spec;
+ g_return_val_if_fail (g_type_is_a (object_type, TYPE_ADMINISTRATION_CLIENT), NULL);
+ spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
+ G_PARAM_SPEC (spec)->value_type = object_type;
+ return G_PARAM_SPEC (spec);
+}
+
+
+gpointer value_get_administration_client (const GValue* value) {
+ g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_CLIENT), NULL);
+ return value->data[0].v_pointer;
+}
+
+
+void value_set_administration_client (GValue* value, gpointer v_object) {
+ AdministrationClient* old;
+ g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_CLIENT));
+ old = value->data[0].v_pointer;
+ if (v_object) {
+ g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADMINISTRATION_CLIENT));
+ g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
+ value->data[0].v_pointer = v_object;
+ administration_client_ref (value->data[0].v_pointer);
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ if (old) {
+ administration_client_unref (old);
+ }
+}
+
+
+void value_take_administration_client (GValue* value, gpointer v_object) {
+ AdministrationClient* old;
+ g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_CLIENT));
+ old = value->data[0].v_pointer;
+ if (v_object) {
+ g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADMINISTRATION_CLIENT));
+ g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
+ value->data[0].v_pointer = v_object;
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ if (old) {
+ administration_client_unref (old);
+ }
+}
+
+
+static void administration_client_class_init (AdministrationClientClass * klass) {
+ administration_client_parent_class = g_type_class_peek_parent (klass);
+ ADMINISTRATION_CLIENT_CLASS (klass)->finalize = administration_client_finalize;
+ g_type_class_add_private (klass, sizeof (AdministrationClientPrivate));
+}
+
+
+static void administration_client_instance_init (AdministrationClient * self) {
+ self->priv = ADMINISTRATION_CLIENT_GET_PRIVATE (self);
+ self->ref_count = 1;
+}
+
+
+static void administration_client_finalize (AdministrationClient* obj) {
+ AdministrationClient * self;
+ self = ADMINISTRATION_CLIENT (obj);
+ _g_object_unref0 (self->priv->_server);
+ _dbus_g_connection_unref0 (self->priv->_connection);
+ (self->priv->_GotProfile_cb_target_destroy_notify == NULL) ? NULL : (self->priv->_GotProfile_cb_target_destroy_notify (self->priv->_GotProfile_cb_target), NULL);
+ self->priv->_GotProfile_cb = NULL;
+ self->priv->_GotProfile_cb_target = NULL;
+ self->priv->_GotProfile_cb_target_destroy_notify = NULL;
+}
+
+
+GType administration_client_get_type (void) {
+ static volatile gsize administration_client_type_id__volatile = 0;
+ if (g_once_init_enter (&administration_client_type_id__volatile)) {
+ static const GTypeValueTable g_define_type_value_table = { value_administration_client_init, value_administration_client_free_value, value_administration_client_copy_value, value_administration_client_peek_pointer, "p", value_administration_client_collect_value, "p", value_administration_client_lcopy_value };
+ static const GTypeInfo g_define_type_info = { sizeof (AdministrationClientClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) administration_client_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (AdministrationClient), 0, (GInstanceInitFunc) administration_client_instance_init, &g_define_type_value_table };
+ static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
+ GType administration_client_type_id;
+ administration_client_type_id = g_type_register_fundamental (g_type_fundamental_next (), "AdministrationClient", &g_define_type_info, &g_define_type_fundamental_info, 0);
+ g_once_init_leave (&administration_client_type_id__volatile, administration_client_type_id);
+ }
+ return administration_client_type_id__volatile;
+}
+
+
+gpointer administration_client_ref (gpointer instance) {
+ AdministrationClient* self;
+ self = instance;
+ g_atomic_int_inc (&self->ref_count);
+ return instance;
+}
+
+
+void administration_client_unref (gpointer instance) {
+ AdministrationClient* self;
+ self = instance;
+ if (g_atomic_int_dec_and_test (&self->ref_count)) {
+ ADMINISTRATION_CLIENT_GET_CLASS (self)->finalize (self);
+ g_type_free_instance ((GTypeInstance *) self);
+ }
+}
+
+
+AdministrationServer* administration_server_construct (GType object_type, const char* address, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target) {
+ GError * _inner_error_;
+ AdministrationServer* self;
+ Administration* _tmp2_;
+ g_return_val_if_fail (address != NULL, NULL);
+ _inner_error_ = NULL;
+ self = (AdministrationServer*) g_type_create_instance (object_type);
+ {
+ DBusGConnection* _tmp0_;
+ DBusGConnection* _tmp1_;
+ _tmp0_ = dbus_g_connection_open (address, &_inner_error_);
+ if (_inner_error_ != NULL) {
+ goto __catch2_g_error;
+ }
+ self->priv->_connection = (_tmp1_ = _tmp0_, _dbus_g_connection_unref0 (self->priv->_connection), _tmp1_);
+ }
+ goto __finally2;
+ __catch2_g_error:
+ {
+ GError * _error_;
+ _error_ = _inner_error_;
+ _inner_error_ = NULL;
+ {
+ g_warning ("sugar_share.vala:165: Cannot open DBus connection: %s", _error_->message);
+ _g_error_free0 (_error_);
+ return self;
+ }
+ }
+ __finally2:
+ if (_inner_error_ != NULL) {
+ g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, _inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+ g_clear_error (&_inner_error_);
+ return NULL;
+ }
+ self->priv->_server = (_tmp2_ = administration_new (GetProfile_cb, GetProfile_cb_target, Report_cb, Report_cb_target), _g_object_unref0 (self->priv->_server), _tmp2_);
+ _vala_dbus_register_object (dbus_g_connection_get_connection (self->priv->_connection), _PATH, (GObject*) self->priv->_server);
+ return self;
+}
+
+
+AdministrationServer* administration_server_new (const char* address, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target) {
+ return administration_server_construct (TYPE_ADMINISTRATION_SERVER, address, GetProfile_cb, GetProfile_cb_target, Report_cb, Report_cb_target);
+}
+
+
+void administration_server_update_profile (AdministrationServer* self) {
+ g_return_if_fail (self != NULL);
+ if (self->priv->_server == NULL) {
+ return;
+ }
+ g_debug ("sugar_share.vala:179: Force to update students profiles");
+ g_signal_emit_by_name (self->priv->_server, "update-profile");
+}
+
+
+static void value_administration_server_init (GValue* value) {
+ value->data[0].v_pointer = NULL;
+}
+
+
+static void value_administration_server_free_value (GValue* value) {
+ if (value->data[0].v_pointer) {
+ administration_server_unref (value->data[0].v_pointer);
+ }
+}
+
+
+static void value_administration_server_copy_value (const GValue* src_value, GValue* dest_value) {
+ if (src_value->data[0].v_pointer) {
+ dest_value->data[0].v_pointer = administration_server_ref (src_value->data[0].v_pointer);
+ } else {
+ dest_value->data[0].v_pointer = NULL;
+ }
+}
+
+
+static gpointer value_administration_server_peek_pointer (const GValue* value) {
+ return value->data[0].v_pointer;
+}
+
+
+static gchar* value_administration_server_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
+ if (collect_values[0].v_pointer) {
+ AdministrationServer* object;
+ object = collect_values[0].v_pointer;
+ if (object->parent_instance.g_class == NULL) {
+ return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
+ } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) {
+ return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL);
+ }
+ value->data[0].v_pointer = administration_server_ref (object);
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ return NULL;
+}
+
+
+static gchar* value_administration_server_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) {
+ AdministrationServer** object_p;
+ object_p = collect_values[0].v_pointer;
+ if (!object_p) {
+ return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
+ }
+ if (!value->data[0].v_pointer) {
+ *object_p = NULL;
+ } else if (collect_flags && G_VALUE_NOCOPY_CONTENTS) {
+ *object_p = value->data[0].v_pointer;
+ } else {
+ *object_p = administration_server_ref (value->data[0].v_pointer);
+ }
+ return NULL;
+}
+
+
+GParamSpec* param_spec_administration_server (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) {
+ ParamSpecAdministrationServer* spec;
+ g_return_val_if_fail (g_type_is_a (object_type, TYPE_ADMINISTRATION_SERVER), NULL);
+ spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags);
+ G_PARAM_SPEC (spec)->value_type = object_type;
+ return G_PARAM_SPEC (spec);
+}
+
+
+gpointer value_get_administration_server (const GValue* value) {
+ g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_SERVER), NULL);
+ return value->data[0].v_pointer;
+}
+
+
+void value_set_administration_server (GValue* value, gpointer v_object) {
+ AdministrationServer* old;
+ g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_SERVER));
+ old = value->data[0].v_pointer;
+ if (v_object) {
+ g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADMINISTRATION_SERVER));
+ g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
+ value->data[0].v_pointer = v_object;
+ administration_server_ref (value->data[0].v_pointer);
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ if (old) {
+ administration_server_unref (old);
+ }
+}
+
+
+void value_take_administration_server (GValue* value, gpointer v_object) {
+ AdministrationServer* old;
+ g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, TYPE_ADMINISTRATION_SERVER));
+ old = value->data[0].v_pointer;
+ if (v_object) {
+ g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, TYPE_ADMINISTRATION_SERVER));
+ g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value)));
+ value->data[0].v_pointer = v_object;
+ } else {
+ value->data[0].v_pointer = NULL;
+ }
+ if (old) {
+ administration_server_unref (old);
+ }
+}
+
+
+static void administration_server_class_init (AdministrationServerClass * klass) {
+ administration_server_parent_class = g_type_class_peek_parent (klass);
+ ADMINISTRATION_SERVER_CLASS (klass)->finalize = administration_server_finalize;
+ g_type_class_add_private (klass, sizeof (AdministrationServerPrivate));
+}
+
+
+static void administration_server_instance_init (AdministrationServer * self) {
+ self->priv = ADMINISTRATION_SERVER_GET_PRIVATE (self);
+ self->ref_count = 1;
+}
+
+
+static void administration_server_finalize (AdministrationServer* obj) {
+ AdministrationServer * self;
+ self = ADMINISTRATION_SERVER (obj);
+ _g_object_unref0 (self->priv->_server);
+ _dbus_g_connection_unref0 (self->priv->_connection);
+}
+
+
+GType administration_server_get_type (void) {
+ static volatile gsize administration_server_type_id__volatile = 0;
+ if (g_once_init_enter (&administration_server_type_id__volatile)) {
+ static const GTypeValueTable g_define_type_value_table = { value_administration_server_init, value_administration_server_free_value, value_administration_server_copy_value, value_administration_server_peek_pointer, "p", value_administration_server_collect_value, "p", value_administration_server_lcopy_value };
+ static const GTypeInfo g_define_type_info = { sizeof (AdministrationServerClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) administration_server_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (AdministrationServer), 0, (GInstanceInitFunc) administration_server_instance_init, &g_define_type_value_table };
+ static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) };
+ GType administration_server_type_id;
+ administration_server_type_id = g_type_register_fundamental (g_type_fundamental_next (), "AdministrationServer", &g_define_type_info, &g_define_type_fundamental_info, 0);
+ g_once_init_leave (&administration_server_type_id__volatile, administration_server_type_id);
+ }
+ return administration_server_type_id__volatile;
+}
+
+
+gpointer administration_server_ref (gpointer instance) {
+ AdministrationServer* self;
+ self = instance;
+ g_atomic_int_inc (&self->ref_count);
+ return instance;
+}
+
+
+void administration_server_unref (gpointer instance) {
+ AdministrationServer* self;
+ self = instance;
+ if (g_atomic_int_dec_and_test (&self->ref_count)) {
+ ADMINISTRATION_SERVER_GET_CLASS (self)->finalize (self);
+ g_type_free_instance ((GTypeInstance *) self);
+ }
+}
+
+
+static void _vala_dbus_register_object (DBusConnection* connection, const char* path, void* object) {
+ const _DBusObjectVTable * vtable;
+ vtable = g_type_get_qdata (G_TYPE_FROM_INSTANCE (object), g_quark_from_static_string ("DBusObjectVTable"));
+ if (vtable) {
+ vtable->register_object (connection, path, object);
+ } else {
+ g_warning ("Object does not implement any D-Bus interface");
+ }
+}
+
+
+static void _vala_dbus_unregister_object (gpointer connection, GObject* object) {
+ char* path;
+ path = g_object_steal_data ((GObject*) object, "dbus_object_path");
+ dbus_connection_unregister_object_path (connection, path);
+ g_free (path);
+}
+
+
+
+
diff --git a/src/gcompris/sugar_share.h b/src/gcompris/sugar_share.h
new file mode 100644
index 0000000..c5ca243
--- /dev/null
+++ b/src/gcompris/sugar_share.h
@@ -0,0 +1,113 @@
+/* sugar_share.h generated by valac, the Vala compiler, do not modify */
+
+
+#ifndef __SUGAR_SHARE_H__
+#define __SUGAR_SHARE_H__
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+
+#define TYPE_ADMINISTRATION (administration_get_type ())
+#define ADMINISTRATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ADMINISTRATION, Administration))
+#define ADMINISTRATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ADMINISTRATION, AdministrationClass))
+#define IS_ADMINISTRATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ADMINISTRATION))
+#define IS_ADMINISTRATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_ADMINISTRATION))
+#define ADMINISTRATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_ADMINISTRATION, AdministrationClass))
+
+typedef struct _Administration Administration;
+typedef struct _AdministrationClass AdministrationClass;
+typedef struct _AdministrationPrivate AdministrationPrivate;
+
+#define TYPE_ADMINISTRATION_CLIENT (administration_client_get_type ())
+#define ADMINISTRATION_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ADMINISTRATION_CLIENT, AdministrationClient))
+#define ADMINISTRATION_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ADMINISTRATION_CLIENT, AdministrationClientClass))
+#define IS_ADMINISTRATION_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ADMINISTRATION_CLIENT))
+#define IS_ADMINISTRATION_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_ADMINISTRATION_CLIENT))
+#define ADMINISTRATION_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_ADMINISTRATION_CLIENT, AdministrationClientClass))
+
+typedef struct _AdministrationClient AdministrationClient;
+typedef struct _AdministrationClientClass AdministrationClientClass;
+typedef struct _AdministrationClientPrivate AdministrationClientPrivate;
+
+#define TYPE_ADMINISTRATION_SERVER (administration_server_get_type ())
+#define ADMINISTRATION_SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_ADMINISTRATION_SERVER, AdministrationServer))
+#define ADMINISTRATION_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_ADMINISTRATION_SERVER, AdministrationServerClass))
+#define IS_ADMINISTRATION_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_ADMINISTRATION_SERVER))
+#define IS_ADMINISTRATION_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_ADMINISTRATION_SERVER))
+#define ADMINISTRATION_SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_ADMINISTRATION_SERVER, AdministrationServerClass))
+
+typedef struct _AdministrationServer AdministrationServer;
+typedef struct _AdministrationServerClass AdministrationServerClass;
+typedef struct _AdministrationServerPrivate AdministrationServerPrivate;
+
+typedef char* (*GetProfileCallback) (void* user_data);
+typedef void (*ReportCallback) (const char* date, gint duration, const char* user, const char* board, gint level, gint sublevel, gint status, const char* comment, void* user_data);
+typedef void (*GotProfileCallback) (const char* data, void* user_data);
+struct _Administration {
+ GObject parent_instance;
+ AdministrationPrivate * priv;
+};
+
+struct _AdministrationClass {
+ GObjectClass parent_class;
+};
+
+struct _AdministrationClient {
+ GTypeInstance parent_instance;
+ volatile int ref_count;
+ AdministrationClientPrivate * priv;
+};
+
+struct _AdministrationClientClass {
+ GTypeClass parent_class;
+ void (*finalize) (AdministrationClient *self);
+};
+
+struct _AdministrationServer {
+ GTypeInstance parent_instance;
+ volatile int ref_count;
+ AdministrationServerPrivate * priv;
+};
+
+struct _AdministrationServerClass {
+ GTypeClass parent_class;
+ void (*finalize) (AdministrationServer *self);
+};
+
+
+GType administration_get_type (void);
+Administration* administration_new (GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target);
+Administration* administration_construct (GType object_type, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target);
+char* administration_GetProfile (Administration* self);
+void administration_Report (Administration* self, const char* date, gint duration, const char* user, const char* board, gint level, gint sublevel, gint status, const char* comment);
+gpointer administration_client_ref (gpointer instance);
+void administration_client_unref (gpointer instance);
+GParamSpec* param_spec_administration_client (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags);
+void value_set_administration_client (GValue* value, gpointer v_object);
+void value_take_administration_client (GValue* value, gpointer v_object);
+gpointer value_get_administration_client (const GValue* value);
+GType administration_client_get_type (void);
+AdministrationClient* administration_client_new (const char* address, const char* name, GotProfileCallback GotProfile_cb, void* GotProfile_cb_target);
+AdministrationClient* administration_client_construct (GType object_type, const char* address, const char* name, GotProfileCallback GotProfile_cb, void* GotProfile_cb_target);
+void administration_client_import_profile (AdministrationClient* self);
+void administration_client_report (AdministrationClient* self, const char* date, gint duration, const char* user, const char* board, gint level, gint sublevel, gint status, const char* comment);
+gpointer administration_server_ref (gpointer instance);
+void administration_server_unref (gpointer instance);
+GParamSpec* param_spec_administration_server (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags);
+void value_set_administration_server (GValue* value, gpointer v_object);
+void value_take_administration_server (GValue* value, gpointer v_object);
+gpointer value_get_administration_server (const GValue* value);
+GType administration_server_get_type (void);
+AdministrationServer* administration_server_new (const char* address, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target);
+AdministrationServer* administration_server_construct (GType object_type, const char* address, GetProfileCallback GetProfile_cb, void* GetProfile_cb_target, ReportCallback Report_cb, void* Report_cb_target);
+void administration_server_update_profile (AdministrationServer* self);
+
+
+G_END_DECLS
+
+#endif
diff --git a/src/gcompris/sugar_share.vala b/src/gcompris/sugar_share.vala
new file mode 100644
index 0000000..2c9a6e0
--- /dev/null
+++ b/src/gcompris/sugar_share.vala
@@ -0,0 +1,186 @@
+/* gcompris - sugar_share.vala
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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/>.
+ */
+
+private const string _PATH = "/org/gcompris/Administration";
+private const string _IFACE = "org.gcompris.Administration";
+
+public delegate string GetProfileCallback ();
+public delegate void ReportCallback (string date, int duration, string user,
+ string board, int level, int sublevel, int status, string comment);
+public delegate void GotProfileCallback (string? data);
+
+/**
+ * DBus service to interact between Administration teacher activity and
+ * students' GCompris sessions
+ */
+[DBus (name = "org.gcompris.Administration")]
+public class Administration : Object {
+ /**
+ * Teacher's profile was changed
+ *
+ * Used by students to know when new teacher's profile should be imported.
+ */
+ public signal void UpdateProfile ();
+
+ /**
+ * @param profile teacher's profile
+ */
+ public Administration (GetProfileCallback GetProfile_cb,
+ ReportCallback Report_cb) {
+ _GetProfile_cb = GetProfile_cb;
+ _Report_cb = Report_cb;
+ }
+
+ /**
+ * Return teacher's profile
+ */
+ public string GetProfile () {
+ debug ("GetProfile called on server");
+ return _GetProfile_cb ();
+ }
+
+ /**
+ * Count student's report
+ */
+ public void Report (string date, int duration, string user, string board,
+ int level, int sublevel, int status, string comment) {
+ debug ("Report called on server");
+ _Report_cb (date, duration, user, board, level, sublevel, status,
+ comment);
+ }
+
+ private GetProfileCallback _GetProfile_cb;
+ private ReportCallback _Report_cb;
+}
+
+/**
+ * Highlevel client interface to Administration DBus service
+ */
+public class AdministrationClient {
+ /**
+ * Create an instance
+ *
+ * @param address DBus connection address
+ * @param name DBus name of the server
+ */
+ public AdministrationClient (string address, string name,
+ GotProfileCallback GotProfile_cb) {
+ _GotProfile_cb = GotProfile_cb;
+
+ try {
+ _connection = DBus.Bus.open (address);
+ } catch (Error error) {
+ warning ("Cannot open DBus connection: %s", error.message);
+ return;
+ }
+
+ _server = _connection.get_object (name, _PATH, _IFACE);
+ _server.UpdateProfile.connect (_UpdateProfile_cb);
+ }
+
+ /**
+ * Start importing profile from Administration server
+ */
+ public void import_profile () {
+ if (_server == null)
+ return;
+
+ debug ("GetProfile called on client");
+
+ try {
+ _server.GetProfile (_GetProfile_cb);
+ } catch (Error error) {
+ warning ("Cannot get server profile: %s", error.message);
+ _GotProfile_cb (null);
+ }
+ }
+
+ /**
+ * Send report to the server
+ */
+ public void report (string date, int duration, string user, string board,
+ int level, int sublevel, int status, string comment) {
+ if (_server == null)
+ return;
+
+ debug ("Send report");
+
+ _server.Report (date, duration, user, board, level, sublevel, status,
+ comment, _Report_cb);
+ }
+
+ private void _Report_cb (Error error) {
+ if (error != null) {
+ warning ("Cannot send report to server: %s", error.message);
+ }
+ }
+
+ private void _GetProfile_cb (string profile_data, Error error) {
+ if (error != null) {
+ warning ("Cannot get server profile: %s", error.message);
+ _GotProfile_cb (null);
+ } else {
+ _GotProfile_cb (profile_data);
+ }
+ }
+
+ private void _UpdateProfile_cb (dynamic DBus.Object sender) {
+ import_profile ();
+ }
+
+ private dynamic DBus.Object _server;
+ private DBus.Connection _connection;
+ private GotProfileCallback _GotProfile_cb;
+}
+
+/**
+ * Highlevel server object to handle Administration DBus service
+ */
+public class AdministrationServer {
+ /**
+ * Create an instance
+ *
+ * @param address DBus connection address
+ */
+ public AdministrationServer (string address,
+ GetProfileCallback GetProfile_cb, ReportCallback Report_cb) {
+ try {
+ _connection = DBus.Bus.open (address);
+ } catch (Error error) {
+ warning ("Cannot open DBus connection: %s", error.message);
+ return;
+ }
+ _server = new Administration (GetProfile_cb, Report_cb);
+ _connection.register_object (_PATH, _server);
+ }
+
+ /**
+ * Emit remote UpdateProfile signal to force students update their profiles
+ */
+ public void update_profile () {
+ if (_server == null)
+ return;
+
+ debug ("Force to update students profiles");
+
+ _server.UpdateProfile ();
+ }
+
+ private dynamic Administration _server;
+ private DBus.Connection _connection;
+}
diff --git a/src/gcompris/sugar_srv.c b/src/gcompris/sugar_srv.c
new file mode 100644
index 0000000..0f300ee
--- /dev/null
+++ b/src/gcompris/sugar_srv.c
@@ -0,0 +1,160 @@
+/* gcompris - sugar_srv.c
+ *
+ * Copyright (C) 2010, Aleksey Lim
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <polyol/toolkit.h>
+
+#include "gcompris.h"
+#include "gc_core.h"
+#include "status.h"
+#include "sugar.h"
+#include "sugar_db.h"
+#include "sugar_share.h"
+
+static void construct();
+static void finalize();
+static void scope_changed_cb(SugarConnection*, SugarShareScope, const gchar*);
+static void channel_appeared_cb(SugarConnection*, SugarChannel*);
+static char* get_profile_request_cb(void*);
+static void report_cb (const char*, gint, const char*, const char*, gint, gint,
+ gint, const char*, void*);
+static void offer_failed_cb(SugarConnection*, const gchar *bus_name);
+
+static GKeyFile *export_profile;
+static gint imported_profile = 1;
+static AdministrationServer *server;
+static time_t last_db_mtime;
+
+Peer srv_peer = {
+ construct,
+ finalize,
+ NULL,
+ NULL
+};
+
+gint
+sugar_get_profile_id()
+{
+ return imported_profile;
+}
+
+static void
+construct()
+{
+ export_profile = g_key_file_new();
+
+ SugarConnection *conn = sugar_activity_get_connection(activity);
+
+ g_signal_connect(conn, "scope-changed", G_CALLBACK(scope_changed_cb), NULL);
+ g_signal_connect(conn, "channel-appeared", G_CALLBACK(channel_appeared_cb),
+ NULL);
+ g_signal_connect(conn, "offer-failed", G_CALLBACK(offer_failed_cb), NULL);
+
+ sugar_db_open();
+
+ GKeyFile *profile = g_key_file_new();
+ SugarJobject *jobject = sugar_activity_get_jobject(activity);
+ const char *file_path = sugar_jobject_get_file_path(jobject);
+
+ if (file_path)
+ g_key_file_load_from_file(profile, file_path, 0, NULL);
+ imported_profile = sugar_db_write(profile);
+
+ g_key_file_free(profile);
+}
+
+static void
+finalize()
+{
+ GKeyFile *profile = g_key_file_new();
+ sugar_db_read(profile, imported_profile);
+ sugar_db_read_reports(profile);
+ save_profile(profile);
+ g_key_file_free(profile);
+
+ if (server != NULL)
+ administration_server_unref(server);
+ server = NULL;
+
+ g_key_file_free(export_profile);
+ export_profile = NULL;
+
+ sugar_db_close(imported_profile);
+}
+
+static void
+scope_changed_cb(SugarConnection *conn, SugarShareScope prev_scope,
+ const gchar *error)
+{
+ if (sugar_connection_get_scope(conn) == SUGAR_SHARE_SCOPE_PRIVATE)
+ {
+ if (server != NULL)
+ administration_server_unref(server);
+ server = NULL;
+ }
+ else
+ {
+ sugar_connection_offer_channel(conn, "org.gcompris.Administration.Channel");
+ g_debug ("Sugar channel creation was initiated");
+ }
+}
+
+static void
+channel_appeared_cb(SugarConnection *conn, SugarChannel *channel)
+{
+ const gchar *address = sugar_channel_get_address(channel);
+ server = administration_server_new(address,
+ get_profile_request_cb, NULL, report_cb, NULL);
+
+ g_debug ("Server sugar channel is online");
+}
+
+static char*
+get_profile_request_cb(void* user_data)
+{
+ struct stat st = { };
+ if ((stat(gc_prop_get()->database, &st) == 0 && st.st_mtime != last_db_mtime)
+ || last_db_mtime == 0)
+ {
+ sugar_db_read(export_profile, imported_profile);
+ last_db_mtime = st.st_mtime;
+ }
+
+ return g_key_file_to_data(export_profile, NULL, NULL);
+}
+
+static void
+report_cb (const char *date, gint duration, const char *user, const char *board,
+ gint level, gint sublevel, gint status, const char *comment,
+ void *user_data)
+{
+ sugar_db_write_report(date, duration, user, board, level, sublevel, status,
+ comment);
+}
+
+static void
+offer_failed_cb(SugarConnection *conn, const gchar *bus_name)
+{
+ SugarAlert *alert = SUGAR_ALERT(sugar_notify_alert_new(_("Sharing Error"),
+ _("Cannot initiate sharing session"), "emblem-warning", 7));
+ sugar_alert_bin_push(alert);
+ sugar_connection_set_scope(conn, SUGAR_SHARE_SCOPE_PRIVATE);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]