/soc/2015/igor.gajowiak/chatlog: 227f25d5bef9: Implemented searc...

Igor Gajowiak <[email protected]>
Newsgroups gmane.comp.gnome.gaim.cvs
Message-ID <[email protected]>
Changeset: 227f25d5bef9715bf5d16b9950b0d2cd3344e2cc
Author:	 Igor Gajowiak <[email protected]>
Date:	 2015-08-11 23:29 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/227f25d5bef9

Description:

Implemented searching for messages containing given phrase.

diffstat:

 libpurple/genericlog.c            |   11 +
 libpurple/genericlog.h            |   28 ++++
 libpurple/plugins/log/logsqlite.c |   66 ++++++++++
 pidgin/gtkgenericlog.c            |  246 ++++++++++++++++++++++++++++++++++---
 pidgin/gtkgenericlog.h            |   12 +
 5 files changed, 338 insertions(+), 25 deletions(-)

diffs (truncated from 636 to 300 lines):

diff --git a/libpurple/genericlog.c b/libpurple/genericlog.c
--- a/libpurple/genericlog.c
+++ b/libpurple/genericlog.c
@@ -311,6 +311,16 @@ purple_genericlog_get_older_msgs(PurpleB
 }
 
 gboolean
+purple_genericlog_find_msgs(PurpleBlistNode *contact, const gchar* pattern,
+	guint limit, guint offset, GList** result, GError** error)
+{
+	DEFINE_GENERICLOG_FUNC_WITH_RETURN(find_msgs,
+		"%s does not support searching messages",
+		"Searching messages from %s failed",
+		contact, pattern, limit, offset, result);
+}
+
+gboolean
 purple_genericlog_get_all_contacts(GList** result, GError** error)
 {
 	DEFINE_GENERICLOG_FUNC_WITH_RETURN(get_all_contacts,
@@ -566,6 +576,7 @@ purple_genericlog_class_init(PurpleGener
 	klass->get_all_contacts = NULL;
 	klass->get_all_days = NULL;
 	klass->wipe_log_for_contact = NULL;
+	klass->find_msgs = NULL;
 	klass->init_export = NULL;
 	klass->read_chunk = NULL;
 	klass->finalize_export = NULL;
diff --git a/libpurple/genericlog.h b/libpurple/genericlog.h
--- a/libpurple/genericlog.h
+++ b/libpurple/genericlog.h
@@ -74,6 +74,9 @@ struct _PurpleGenericLog
  *                   then upper bound check is skipped. Messages are sorted
  *                   by their timestamp in descending order.
  *                   Returns %TRUE if operation succeeds, %FALSE otherwise.
+ * @find_msgs:       Gets a list of messages sent to or received from a given
+ *                   contact containing given phrase. Messages should be sorted
+ *                   by their timestamp in descending order.
  * @get_all_contacts: Gets a list of all #PurpleBlistNode objects with at least
  *                    one message in the log. Returns %TRUE if operation
  *                    succeeds, %FALSE otherwise. The client is responsible for
@@ -127,6 +130,9 @@ struct _PurpleGenericLogClass
 	gboolean (*get_older_msgs)(PurpleBlistNode *contact, guint64 timestamp,
 		PurpleMessage *message, GList **result);
 
+	gboolean (*find_msgs)(PurpleBlistNode *contact, const gchar* pattern,
+		guint limit, guint offset, GList **result);
+
 	gboolean (*get_all_contacts)(GList **result);
 
 	gboolean (*get_all_days)(PurpleBlistNode *contact, GArray **result);
@@ -354,6 +360,28 @@ purple_genericlog_get_older_msgs(PurpleB
 	PurpleMessage *message, GList **result, GError **error);
 
 /**
+ * purple_genericlog_find_msgs:
+ * @contact:     The contact, must be PurpleChat or PurpleBuddy.
+ * @phrase:      The phrase to search for.
+ * @limit:       The limit of the size of the result.
+ * @offset:      The number of messages to skip.
+ * @result[out]: The return location for the result. Contains objects of
+ *               type #PurpleMessage.
+ * @error:       Return location for a #GError or %NULL. If provided, this
+ *               will be set to the reason if getting messages fails.
+ *
+ * Gets a list of messages sent to or received from a given contact containing
+ * given phrase from the active log.
+ *
+ * Messages are sorted by their timestamp in descending order.
+ *
+ * Returns: %TRUE if succeeds, %FALSE otherwise.
+ */
+gboolean
+purple_genericlog_find_msgs(PurpleBlistNode *contact, const gchar* phrase,
+	guint limit, guint offset, GList **result, GError **error);
+
+/**
  * purple_genericlog_get_all_contacts:
  * @result[out]: Return location for a #GList containing a list of #PurpleBuddy
  *               objects. This will not be set in case of any errors.
diff --git a/libpurple/plugins/log/logsqlite.c b/libpurple/plugins/log/logsqlite.c
--- a/libpurple/plugins/log/logsqlite.c
+++ b/libpurple/plugins/log/logsqlite.c
@@ -216,6 +216,22 @@ typedef enum
 	GET_OLDER_MSGS_UPPER_QUERY_PARAM_EXCEPTID   = 4,
 } GetOlderMsgsUpperQueryParam;
 
+static sqlite3_stmt *find_msgs_q = NULL;
+
+static const char *find_msgs_q_str =
+	"SELECT Id, Author, AuthorAlias, Recipient, Contents, MsgTime, Flags "
+	"FROM Messages "
+	"WHERE ContactId = ?1 AND Contents LIKE '%' || ?2 || '%' "
+	"ORDER BY MsgTime DESC, Id DESC LIMIT ?3 OFFSET ?4;";
+
+typedef enum
+{
+	FIND_MSGS_QUERY_PARAM_CONTACTYID = 1,
+	FIND_MSGS_QUERY_PARAM_PATTERN    = 2,
+	FIND_MSGS_QUERY_PARAM_LIMIT      = 3,
+	FIND_MSGS_QUERY_PARAM_OFFSET     = 4,
+} FindMsgsQueryParam;
+
 typedef enum
 {
 	GET_MSGS_QUERY_COL_ID          = 0,
@@ -306,6 +322,7 @@ sqlitelog_finalize_queries()
 	sqlitelog_finalize_query(&get_all_msgs_q);
 	sqlitelog_finalize_query(&get_older_msgs_q);
 	sqlitelog_finalize_query(&get_older_msgs_upper_q);
+	sqlitelog_finalize_query(&find_msgs_q);
 	sqlitelog_finalize_query(&mark_as_seen_q);
 	sqlitelog_finalize_query(&get_all_contacts_q);
 	sqlitelog_finalize_query(&get_all_days_q);
@@ -354,6 +371,7 @@ sqlitelog_prepare_queries()
 		!sqlitelog_prepare_query(get_older_msgs_q_str, &get_older_msgs_q) ||
 		!sqlitelog_prepare_query(get_older_msgs_upper_q_str,
 			&get_older_msgs_upper_q) ||
+		!sqlitelog_prepare_query(find_msgs_q_str, &find_msgs_q) ||
 		!sqlitelog_prepare_query(mark_as_seen_q_str, &mark_as_seen_q) ||
 		!sqlitelog_prepare_query(get_all_contacts_q_str, &get_all_contacts_q) ||
 		!sqlitelog_prepare_query(get_all_days_q_str, &get_all_days_q) ||
@@ -928,6 +946,37 @@ sqlitelog_get_older_msgs_upper_impl(Purp
 }
 
 static gboolean
+sqlitelog_find_msgs_impl(PurpleBlistNode *contact, const gchar *pattern,
+	guint limit, guint offset, GList **result)
+{
+	g_assert(contact);
+	g_assert(pattern);
+	g_assert(result);
+
+	guint contact_id;
+	if (!sqlitelog_get_contact_id_from_obj(contact, &contact_id))
+		return FALSE;
+
+	if (contact_id == SQLITELOG_DB_ID_NONE) {
+		*result = NULL;
+		return TRUE;
+	}
+
+	if (sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_CONTACTYID,
+			contact_id) != SQLITE_OK ||
+		sqlite3_bind_text(find_msgs_q, FIND_MSGS_QUERY_PARAM_PATTERN,
+			pattern, -1, SQLITE_STATIC) != SQLITE_OK ||
+		sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_LIMIT, limit)
+			!= SQLITE_OK ||
+		sqlite3_bind_int64(find_msgs_q, FIND_MSGS_QUERY_PARAM_OFFSET, offset)
+			!= SQLITE_OK) {
+		return FALSE;
+	}
+
+	return sqlitelog_execute_get_msgs_query(find_msgs_q, result);
+}
+
+static gboolean
 sqlitelog_mark_as_seen_impl(unsigned msg_id)
 {
 	g_assert(msg_id != SQLITELOG_DB_ID_NONE);
@@ -1282,6 +1331,22 @@ sqlitelog_get_older_msgs(PurpleBlistNode
 }
 
 static gboolean
+sqlitelog_find_msgs(PurpleBlistNode *contact, const gchar *pattern, guint limit,
+	guint offset, GList **result)
+{
+	g_return_val_if_fail(contact != NULL, FALSE);
+	g_return_val_if_fail(pattern != NULL, FALSE);
+	g_return_val_if_fail(result != NULL, FALSE);
+
+	if (!sqlitelog_db_handle) {
+		purple_debug_error(SQLITELOG_DEBUG_CATEGORY, "Log is not active");
+		return FALSE;
+	}
+
+	return sqlitelog_find_msgs_impl(contact, pattern, limit, offset, result);
+}
+
+static gboolean
 sqlitelog_get_all_contacts(GList **result)
 {
 	g_return_val_if_fail(result != NULL, FALSE);
@@ -1370,6 +1435,7 @@ purple_sqlitelog_class_init (PurpleSqlit
 	klass->parent_class.get_unseen_msgs = sqlitelog_get_unseen_msgs;
 	klass->parent_class.get_all_msgs = sqlitelog_get_all_msgs;
 	klass->parent_class.get_older_msgs = sqlitelog_get_older_msgs;
+	klass->parent_class.find_msgs = sqlitelog_find_msgs;
 	klass->parent_class.get_all_contacts = sqlitelog_get_all_contacts;
 	klass->parent_class.get_all_days = sqlitelog_get_all_days;
 	klass->parent_class.wipe_log_for_contact =
diff --git a/pidgin/gtkgenericlog.c b/pidgin/gtkgenericlog.c
--- a/pidgin/gtkgenericlog.c
+++ b/pidgin/gtkgenericlog.c
@@ -30,6 +30,7 @@
 #include "gtkwebview.h"
 
 #define GTKGENERICLOG_DEBUG_CATEGORY "gtkgenericlog"
+#define GTKGENERICLOG_SEARCH_CHUNK_SIZE 50
 
 static PidginGenericLogViewer *generic_log_viewer = NULL;
 
@@ -307,10 +308,26 @@ on_reload_item_clicked(GtkAction *action
 		GTK_TREE_MODEL(viewer->blist_tree_store));
 }
 
+static PidginGenericLogMsgFinder*
+create_msg_finder(PidginGenericLogViewer *viewer);
+
+static void
+reset_find_state(PidginGenericLogViewer *viewer);
+
 static void
 on_search_item_clicked(GtkAction *action, gpointer data)
 {
-	printf("on_search_item_clicked\n");
+	g_assert(data);
+
+	PidginGenericLogViewer *viewer = (PidginGenericLogViewer*) data;
+
+	if (!viewer->finder)
+		viewer->finder = create_msg_finder(viewer);
+
+	reset_find_state(viewer);
+
+	gtk_widget_show_all(viewer->finder->window);
+	gtk_widget_grab_focus(viewer->finder->entry);
 }
 
 static void
@@ -348,7 +365,8 @@ on_print_item_clicked(GtkAction *action,
 }
 
 static GtkWidget *
-create_archive_menu_item(PidginGenericLogViewer *viewer)
+create_archive_menu_item(PidginGenericLogViewer *viewer,
+	GtkWidget **search_item_res)
 {
 	g_assert(viewer);
 
@@ -384,6 +402,8 @@ create_archive_menu_item(PidginGenericLo
 	g_signal_connect(G_OBJECT(close_item), "activate",
 		G_CALLBACK(on_close_item_clicked), viewer);
 
+	*search_item_res = search_item;
+
 	return archive_item;
 }
 
@@ -545,13 +565,15 @@ create_contact_menu_item(PidginGenericLo
 static GtkWidget *
 create_menu_bar(PidginGenericLogViewer *viewer,
 	GtkWidget **start_conversation_item_res,
-	GtkWidget **wipe_log_for_contact_item_res)
+	GtkWidget **wipe_log_for_contact_item_res,
+	GtkWidget **search_item_res)
 {
 	g_assert(viewer);
 
 	GtkWidget *menu_bar = gtk_menu_bar_new();
 
-	GtkWidget *archive_item = create_archive_menu_item(viewer);
+	GtkWidget *archive_item = create_archive_menu_item(viewer,
+		search_item_res);
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), archive_item);
 
 	GtkWidget *options_item = create_options_menu_item(viewer);
@@ -569,12 +591,12 @@ update_menu_buttons(PidginGenericLogView
 {
 	g_assert(viewer);
 
-	gboolean start_conv_enabled = TRUE;
-	gboolean wipe_log_enabled = TRUE;
+    gboolean contact_selected = TRUE;
+	gboolean account_enabled = TRUE;
 
 	if (!viewer->current_contact) {
-		start_conv_enabled = FALSE;
-		wipe_log_enabled = FALSE;
+		contact_selected = FALSE;
+		account_enabled = FALSE;
 	}
 	else {
 		PurpleAccount *account = get_account_from_contact(
@@ -582,13 +604,14 @@ update_menu_buttons(PidginGenericLogView
 
 		/* Disable start conversation button if account is disabled */
 		if (!account || !purple_account_get_connection(account))
-			start_conv_enabled = FALSE;
+			account_enabled = FALSE;
 	}
 
 	gtk_widget_set_sensitive(viewer->start_conversation_item,
-		start_conv_enabled);
+		contact_selected && account_enabled);
 	gtk_widget_set_sensitive(viewer->wipe_log_for_contact_item,
-		wipe_log_enabled);
+		contact_selected);
+	gtk_widget_set_sensitive(viewer->search_item, contact_selected);
 }

_______________________________________________
Commits mailing list
[email protected]
https://pidgin.im/cgi-bin/mailman/listinfo/commits
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.