Add purple_notification_manager_remove_with_account.

Mon, 22 Aug 2022 03:20:05 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Mon, 22 Aug 2022 03:20:05 -0500
changeset 41511
2036d450fd18
parent 41510
630da93b9984
child 41512
77c928fde86b

Add purple_notification_manager_remove_with_account.

This is used when an account is disabled or removed to purge its notifications
from the manager.

Testing Done:
Ran the unit tests and forced them to fail with bad values to verify they were correct.

Reviewed at https://reviews.imfreedom.org/r/1612/

libpurple/purplenotificationmanager.c file | annotate | diff | comparison | revisions
libpurple/purplenotificationmanager.h file | annotate | diff | comparison | revisions
libpurple/tests/test_notification_manager.c file | annotate | diff | comparison | revisions
--- a/libpurple/purplenotificationmanager.c	Fri Aug 19 00:27:38 2022 -0500
+++ b/libpurple/purplenotificationmanager.c	Mon Aug 22 03:20:05 2022 -0500
@@ -357,6 +357,94 @@
 	}
 }
 
+/*
+This function uses the following algorithm to optimally remove items from the
+GListStore. See the psuedo code below for an easier to follow version.
+
+A
+A B C
+B C
+A A B C
+B A C
+B A A C
+B C A
+B C A A
+
+set len = number_of_items
+set pos = 0
+set have_same = false
+while pos < len
+  check item at pos
+    if same
+      if not have_same
+        reset count = 0
+        set start = pos
+        set have_same = TRUE
+
+      set count = count + 1
+    else
+      if have_same
+        remove count items from start
+        set pos = pos - count
+        set len = len - count
+        set have_same = FALSE
+  set pos = pos + 1
+if have_same
+  remove count items from start
+*/
+void
+purple_notification_manager_remove_with_account(PurpleNotificationManager *manager,
+                                                PurpleAccount *account)
+{
+	guint pos = 0, len = 0;
+	guint start = 0, count = 0;
+	gboolean have_same = FALSE;
+
+	g_return_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager));
+	g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+	len = g_list_model_get_n_items(G_LIST_MODEL(manager->notifications));
+	for(pos = 0; pos < len; pos++) {
+		PurpleAccount *account2 = NULL;
+		PurpleNotification *notification = NULL;
+
+		notification = g_list_model_get_item(G_LIST_MODEL(manager->notifications),
+		                                     pos);
+
+		account2 = purple_notification_get_account(notification);
+		if(account == account2) {
+			/* If this is the first item with the right account store its position. */
+			if(!have_same) {
+				count = 0;
+				start = pos;
+				have_same = TRUE;
+			}
+
+			/* Increment the count of items starting at the start position. */
+			count++;
+		} else {
+			if(have_same) {
+				/* Remove the run of items from the list. */
+				g_list_store_splice(manager->notifications, start, count, NULL,
+				                    0);
+
+				/* Adjust pos and len for the items that we removed. */
+				pos = pos - count;
+				len = len - count;
+
+				have_same = FALSE;
+			}
+		}
+
+		g_clear_object(&notification);
+	}
+
+	/* Clean up the last bit if the last item needs to be removed. */
+	if(have_same) {
+		g_list_store_splice(manager->notifications, start, count, NULL, 0);
+	}
+}
+
 guint
 purple_notification_manager_get_unread_count(PurpleNotificationManager *manager) {
 	g_return_val_if_fail(PURPLE_IS_NOTIFICATION_MANAGER(manager), 0);
--- a/libpurple/purplenotificationmanager.h	Fri Aug 19 00:27:38 2022 -0500
+++ b/libpurple/purplenotificationmanager.h	Mon Aug 22 03:20:05 2022 -0500
@@ -78,6 +78,17 @@
 void purple_notification_manager_remove(PurpleNotificationManager *manager, PurpleNotification *notification);
 
 /**
+ * purple_notification_manager_remove_with_account:
+ * @manager: The instance.
+ * @account: The [class@Account] whose notifications to remove.
+ *
+ * Removes all notifications with @account from @manager.
+ *
+ * Since: 3.0.0
+ */
+void purple_notification_manager_remove_with_account(PurpleNotificationManager *manager, PurpleAccount *account);
+
+/**
  * purple_notification_manager_get_unread_count:
  * @manager: The instance.
  *
--- a/libpurple/tests/test_notification_manager.c	Fri Aug 19 00:27:38 2022 -0500
+++ b/libpurple/tests/test_notification_manager.c	Mon Aug 22 03:20:05 2022 -0500
@@ -162,6 +162,78 @@
 }
 
 static void
+test_purple_notification_manager_remove_with_account_simple(void) {
+	PurpleNotificationManager *manager = NULL;
+	PurpleNotification *notification = NULL;
+	PurpleAccount *account = NULL;
+	GListModel *model = NULL;
+
+	manager = g_object_new(PURPLE_TYPE_NOTIFICATION_MANAGER, NULL);
+	model = purple_notification_manager_get_model(manager);
+	account = purple_account_new("test", "test");
+
+	/* Make sure that nothing happens on an empty list. */
+	purple_notification_manager_remove_with_account(manager, account);
+	g_assert_cmpuint(0, ==, g_list_model_get_n_items(model));
+
+	/* Add a single notification without the account */
+	notification = purple_notification_new(PURPLE_NOTIFICATION_TYPE_GENERIC,
+	                                       NULL, NULL, NULL);
+	purple_notification_manager_add(manager, notification);
+	purple_notification_manager_remove_with_account(manager, account);
+	g_assert_cmpuint(1, ==, g_list_model_get_n_items(model));
+	g_list_store_remove_all(G_LIST_STORE(model));
+	g_clear_object(&notification);
+
+	/* Add a single notification with the account */
+	notification = purple_notification_new(PURPLE_NOTIFICATION_TYPE_GENERIC,
+	                                       account, NULL, NULL);
+	purple_notification_manager_add(manager, notification);
+	purple_notification_manager_remove_with_account(manager, account);
+	g_assert_cmpuint(0, ==, g_list_model_get_n_items(model));
+	g_list_store_remove_all(G_LIST_STORE(model));
+	g_clear_object(&notification);
+
+	g_clear_object(&manager);
+	g_clear_object(&account);
+}
+
+static void
+test_purple_notification_manager_remove_with_account_mixed(void) {
+	PurpleNotificationManager *manager = NULL;
+	PurpleNotification *notification = NULL;
+	PurpleAccount *accounts[3];
+	GListModel *model = NULL;
+	gint pattern[] = {0, 0, 1, 0, 2, 1, 0, 0, 1, 2, 0, 1, 0, 0, -1};
+	gint i = 0;
+
+	manager = g_object_new(PURPLE_TYPE_NOTIFICATION_MANAGER, NULL);
+	model = purple_notification_manager_get_model(manager);
+
+	accounts[0] = purple_account_new("account1", "account1");
+	accounts[1] = purple_account_new("account2", "account2");
+	accounts[2] = purple_account_new("account3", "account3");
+
+	/* Add our notifications. */
+	for(i = 0; pattern[i] >= 0; i++) {
+		notification = purple_notification_new(PURPLE_NOTIFICATION_TYPE_GENERIC,
+		                                       accounts[pattern[i]], NULL,
+		                                       NULL);
+		purple_notification_manager_add(manager, notification);
+		g_clear_object(&notification);
+	}
+
+	g_assert_cmpuint(14, ==, g_list_model_get_n_items(model));
+	purple_notification_manager_remove_with_account(manager, accounts[0]);
+	g_assert_cmpuint(6, ==, g_list_model_get_n_items(model));
+
+	g_clear_object(&manager);
+	g_clear_object(&accounts[0]);
+	g_clear_object(&accounts[1]);
+	g_clear_object(&accounts[2]);
+}
+
+static void
 test_purple_notification_manager_read_propagation(void) {
 	PurpleNotificationManager *manager = NULL;
 	PurpleNotification *notification = NULL;
@@ -243,6 +315,11 @@
 	g_test_add_func("/notification-manager/double-remove",
 	                test_purple_notification_manager_double_remove);
 
+	g_test_add_func("/notification-manager/remove-with-account/simple",
+	                test_purple_notification_manager_remove_with_account_simple);
+	g_test_add_func("/notification-manager/remove-with-account/mixed",
+	                test_purple_notification_manager_remove_with_account_mixed);
+
 	g_test_add_func("/notification-manager/read-propagation",
 	                test_purple_notification_manager_read_propagation);
 

mercurial