/soc/2015/igor.gajowiak/chatlog: 4e79be028d92: Implemented log i...

Igor Gajowiak igor.gajowiak at gmail.com
Sat Aug 8 14:47:44 EDT 2015


Changeset: 4e79be028d92a4565da3a29de9a8d235f1d65c2e
Author:	 Igor Gajowiak <igor.gajowiak at gmail.com>
Date:	 2015-08-08 20:47 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/4e79be028d92

Description:

Implemented log import UI.

diffstat:

 libpurple/genericlog.c |   18 ++-
 libpurple/genericlog.h |   15 ++-
 pidgin/gtkgenericlog.c |  268 ++++++++++++++++++++++++++++++++++++++++++++++--
 pidgin/gtkgenericlog.h |   17 +++
 4 files changed, 297 insertions(+), 21 deletions(-)

diffs (truncated from 420 to 300 lines):

diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -26,7 +26,11 @@
 #define PURPLE_GENERICLOG_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_GENERICLOG, PurpleGenericLogPrivate))
 
-#define PURPLE_GENERICLOG_IMPORT_CHUNK_SIZE 500
+/* Defines how many messages should be imported in a single chunk */
+#define PURPLE_GENERICLOG_IMPORT_CHUNK_SIZE 200
+
+/* Defines how much time to wait between importing next chunk */
+#define PURPLE_GENERICLOG_IMPORT_TIMESLICE  20
 
 typedef struct
 {
@@ -53,6 +57,7 @@ typedef struct
 {
 	PurpleGenericLog *src_log;
 	PurpleGenericLog_OnImportFinished on_finished;
+	gpointer user_data;
 	void *export_state;
 	guint timer;
 	guint imported_messages_count;
@@ -353,7 +358,8 @@ run_import_iteration(gpointer unused)
 		uninit_import_state(import_state);
 
 		import_state->on_finished(status,
-			import_state->imported_messages_count);
+			import_state->imported_messages_count,
+			import_state->user_data);
 
 		g_free(import_state);
 		import_state = NULL;
@@ -380,7 +386,8 @@ run_import_iteration(gpointer unused)
 
 gboolean
 purple_genericlog_import_msgs(PurpleGenericLog *src_log,
-	PurpleGenericLog_OnImportFinished on_finished, GError **error)
+	PurpleGenericLog_OnImportFinished on_finished, gpointer user_data,
+	GError **error)
 {
 	if (!purple_genericlog_inuse) {
 		if (!error) return FALSE;
@@ -431,10 +438,11 @@ purple_genericlog_import_msgs(PurpleGene
 	import_state = g_new0(PurpleGenericLogImportState, 1);
 	import_state->src_log = src_log;
 	import_state->on_finished = on_finished;
+	import_state->user_data = user_data;
 	import_state->export_state = export_state;
 
-	import_state->timer = purple_timeout_add(1, run_import_iteration,
-		import_state);
+	import_state->timer = purple_timeout_add(PURPLE_GENERICLOG_IMPORT_TIMESLICE,
+		run_import_iteration, import_state);
 
 	return TRUE;
 }
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -140,7 +140,15 @@ struct _PurpleGenericLogClass
 	void (*reserved4)(void);
 };
 
-typedef void (*PurpleGenericLog_OnImportFinished)(gboolean, guint);
+/**
+ * PurpleGenericLog_OnImportFinished:
+ * @1: The status.
+ * @2: The number of imported messages.
+ * @3: The user data.
+ *
+ * Called after import had finished.
+ */
+typedef void (*PurpleGenericLog_OnImportFinished)(gboolean, guint, gpointer);
 
 #define PURPLE_GENERICLOG_DEFAULT "genericlog-sqlitelog"
 
@@ -185,7 +193,7 @@ purple_genericlog_get_name(const PurpleG
  * Returns: A #GList of elements of type #PurpleGenericLog.
  */
 GList*
-purple_genericlog_get_registered_logs();
+purple_genericlog_get_registered_logs(void);
 
 /**
  * purple_genericlog_find_by_id:
@@ -404,7 +412,8 @@ purple_genericlog_wipe_log_for_buddy(Pur
  */
 gboolean
 purple_genericlog_import_msgs(PurpleGenericLog *src_log,
-	PurpleGenericLog_OnImportFinished on_finished, GError **error);
+	PurpleGenericLog_OnImportFinished on_finished, gpointer user_data,
+	GError **error);
 
 /**************************************************************************/
 /* Error Codes                                                            */
diff --git a/pidgin/gtkgenericlog.c b/pidgin/gtkgenericlog.c
--- a/pidgin/gtkgenericlog.c
+++ b/pidgin/gtkgenericlog.c
@@ -34,6 +34,254 @@
 static PidginGenericLogViewer *generic_log_viewer = NULL;
 
 /******************************************************************************/
+/* Import window                                                              */
+/******************************************************************************/
+
+static const gchar * const  labels[] =
+{
+	"Importing   ",
+	"Importing.  ",
+	"Importing.. ",
+	"Importing..."
+};
+
+typedef enum
+{
+	LOGS_LIST_STORE_LOGID = 0,
+	LOGS_LIST_STORE_COLS  = 1,
+} LogsListStore;
+
+static GtkListStore *
+create_logs_store()
+{
+	/* Stores generic log ids */
+	return gtk_list_store_new(LOGS_LIST_STORE_COLS,
+		G_TYPE_STRING);
+}
+
+static void
+populate_logs_store(GtkListStore *store)
+{
+	g_assert(store);
+
+	gtk_list_store_clear(store);
+
+	PurpleGenericLog *inuse = purple_genericlog_get_inuse();
+
+	GList *logs = purple_genericlog_get_registered_logs();
+	for (; logs != NULL; logs = logs->next) {
+		PurpleGenericLog *log = PURPLE_GENERICLOG(logs->data);
+
+		if (log == inuse)
+			continue;
+
+		GtkTreeIter iter;
+		gtk_list_store_append(store, &iter);
+		gtk_list_store_set(store, &iter,
+			LOGS_LIST_STORE_LOGID, purple_genericlog_get_id(log), -1);
+	}
+}
+
+static GtkWidget *
+create_logs_combobox(GtkListStore *store)
+{
+	g_assert(store);
+
+	GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
+
+	GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
+	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE);
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), renderer,
+		"text", 0, NULL);
+
+	return combobox;
+}
+
+static gboolean
+start_import(PidginGenericLogViewer *viewer);
+
+static void
+update_sensitivity(PidginGenericLogViewer *viewer, gboolean sensitive)
+{
+	g_assert(viewer);
+
+	gtk_widget_set_sensitive(viewer->window, sensitive);
+	gtk_widget_set_sensitive(viewer->importer->import_button, sensitive);
+	gtk_widget_set_sensitive(viewer->importer->close_button, sensitive);
+}
+
+static void
+on_import_window_response(GtkWidget *widget, gint resp, gpointer data)
+{
+	g_assert(data);
+
+	PidginGenericLogViewer *viewer = (PidginGenericLogViewer*) data;
+
+	switch (resp) {
+		case GTK_RESPONSE_ACCEPT:
+		{
+			if (start_import(viewer)) {
+				/* Block log window until import is done */
+				update_sensitivity(viewer, FALSE);
+			}
+			return;
+		}
+		case GTK_RESPONSE_CLOSE:
+		{
+			gtk_widget_hide(viewer->importer->window);
+			return;
+		}
+	}
+
+	/* Not reachable */
+	g_assert(FALSE);
+}
+
+static GtkWidget *
+create_import_window(PidginGenericLogViewer *viewer,
+	GtkWindow *parent_window, GtkWidget **logs_combobox_res,
+	GtkListStore **logs_store_res, GtkWidget **status_label_res,
+	GtkWidget **import_button_res, GtkWidget **close_button_res)
+{
+	g_assert(viewer);
+	g_assert(parent_window);
+	g_assert(logs_combobox_res);
+	g_assert(logs_store_res);
+	g_assert(status_label_res);
+	g_assert(import_button_res);
+	g_assert(close_button_res);
+
+	GtkWidget *window = gtk_dialog_new();
+	gtk_window_set_title(GTK_WINDOW(window), "Import messages");
+	gtk_window_set_transient_for(GTK_WINDOW(window), parent_window);
+
+	GtkWidget *import_button = gtk_dialog_add_button(GTK_DIALOG(window),
+		"_Import", GTK_RESPONSE_ACCEPT);
+	GtkWidget *close_button = gtk_dialog_add_button(GTK_DIALOG(window),
+		"_Close", GTK_RESPONSE_CLOSE);
+
+	g_signal_connect(G_OBJECT(window), "response",
+		G_CALLBACK(on_import_window_response), viewer);
+
+	GtkListStore *logs_store = create_logs_store();
+	populate_logs_store(logs_store);
+	GtkWidget *logs_combobox = create_logs_combobox(logs_store);
+	gtk_combo_box_set_active(GTK_COMBO_BOX(logs_combobox), 0);
+	gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))),
+		logs_combobox, FALSE, FALSE, 0);
+
+	GtkWidget *status_label = gtk_label_new("");
+	gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))),
+		status_label, FALSE, FALSE, 0);
+
+	*logs_combobox_res = logs_combobox;
+	*logs_store_res = logs_store;
+	*status_label_res = status_label;
+	*import_button_res = import_button;
+	*close_button_res = close_button;
+
+	return window;
+}
+
+static PidginGenericLogImporter *
+create_log_importer(PidginGenericLogViewer *viewer)
+{
+	PidginGenericLogImporter *importer = g_new0(PidginGenericLogImporter, 1);
+
+	importer->iterator = 0;
+	importer->window = create_import_window(viewer, GTK_WINDOW(viewer->window),
+		&importer->logs_combobox, &importer->logs_store,
+		&importer->status_label, &importer->import_button,
+		&importer->close_button);
+
+	return importer;
+}
+
+static gboolean
+update_importer_label(gpointer data)
+{
+	g_assert(data);
+
+	PidginGenericLogImporter *importer = (PidginGenericLogImporter*) data;
+
+	importer->iterator = (importer->iterator + 1) %
+		(sizeof(labels) / sizeof(labels[0]));
+	gtk_label_set_markup(GTK_LABEL(importer->status_label),
+		labels[importer->iterator]);
+
+	return TRUE;
+}
+
+static void
+on_import_finished(gboolean status, guint msg_count, gpointer data)
+{
+	g_assert(data);
+
+	PidginGenericLogViewer *viewer = (PidginGenericLogViewer*) data;
+	PidginGenericLogImporter *importer = viewer->importer;
+
+	g_assert(importer);
+
+	purple_timeout_remove(importer->timer);
+	importer->iterator = 0;
+
+	const gchar *format = status ? "Import succeeded, imported %u messages\n"
+		: "Error occured during import, imported %u messages\n";
+
+	gchar *text = g_strdup_printf(format, msg_count);
+	gtk_label_set_markup(GTK_LABEL(importer->status_label), text);



More information about the Commits mailing list