pidgin/pidgin

4c7b2771461a
Parents d202e153dd70
Children 4de5a514b8ba
Add PurpleRequestField.is_filled vfunc, and a filled property

And then move the string-specific check into the subclass.

Note that this just does a `g_object_notify(G_OBJECT(field), "filled");` instead of adding a convenience function; not sure if I should do that.

Testing Done:
Compiled and ran `ninja test`.

Reviewed at https://reviews.imfreedom.org/r/2345/
--- a/libpurple/purplerequestfield.c Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/purplerequestfield.c Tue Mar 14 00:42:47 2023 -0500
@@ -21,7 +21,6 @@
#include <glib/gi18n-lib.h>
#include "request.h"
-#include "request/purplerequestfieldstring.h"
#include "purpleprivate.h"
typedef struct {
@@ -50,6 +49,7 @@
PROP_TYPE_HINT,
PROP_TOOLTIP,
PROP_REQUIRED,
+ PROP_FILLED,
PROP_IS_VALIDATABLE,
N_PROPERTIES,
};
@@ -107,6 +107,10 @@
g_value_set_boolean(value,
purple_request_field_is_required(field));
break;
+ case PROP_FILLED:
+ g_value_set_boolean(value,
+ purple_request_field_is_filled(field));
+ break;
case PROP_IS_VALIDATABLE:
g_value_set_boolean(value,
purple_request_field_is_validatable(field));
@@ -280,6 +284,19 @@
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
+ * PurpleRequestField:filled:
+ *
+ * Whether the field has been filled.
+ *
+ * Since: 3.0.0
+ */
+ properties[PROP_FILLED] = g_param_spec_boolean(
+ "filled", "filled",
+ "Whether the field has been filled.",
+ TRUE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+ /**
* PurpleRequestField:is-validatable:
*
* Whether the field can be validated by the requestor.
@@ -473,14 +490,17 @@
gboolean
purple_request_field_is_filled(PurpleRequestField *field) {
+ PurpleRequestFieldClass *klass = NULL;
+ gboolean filled = TRUE;
+
g_return_val_if_fail(PURPLE_IS_REQUEST_FIELD(field), FALSE);
- if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
- return !purple_strempty(purple_request_field_string_get_value(sfield));
+ klass = PURPLE_REQUEST_FIELD_GET_CLASS(field);
+ if(klass != NULL && klass->is_filled != NULL) {
+ filled = klass->is_filled(field);
}
- return TRUE;
+ return filled;
}
void
--- a/libpurple/purplerequestfield.h Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/purplerequestfield.h Tue Mar 14 00:42:47 2023 -0500
@@ -53,6 +53,7 @@
GObjectClass parent_class;
/*< public >*/
+ gboolean (*is_filled)(PurpleRequestField *field);
/*< private >*/
gpointer reserved[4];
@@ -193,7 +194,11 @@
* purple_request_field_is_filled:
* @field: The field.
*
- * Checks, if specified field has value.
+ * Returns whether the field is currently filled.
+ *
+ * Note: For subclassers, if this is not overridden, then the field is assumed
+ * to always be filled. If the filled status changes, then subclasses should
+ * notify on [property@RequestField:filled].
*
* Returns: TRUE if the field has value, or FALSE.
*/
--- a/libpurple/request/purplerequestfieldstring.c Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/request/purplerequestfieldstring.c Tue Mar 14 00:42:47 2023 -0500
@@ -57,6 +57,16 @@
}
/******************************************************************************
+ * PurpleRequestField Implementation
+ *****************************************************************************/
+static gboolean
+purple_request_field_string_is_filled(PurpleRequestField *field) {
+ PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field);
+
+ return !purple_strempty(strfield->value);
+}
+
+/******************************************************************************
* GObject Implementation
*****************************************************************************/
G_DEFINE_TYPE(PurpleRequestFieldString, purple_request_field_string,
@@ -138,8 +148,11 @@
static void
purple_request_field_string_class_init(PurpleRequestFieldStringClass *klass) {
+ PurpleRequestFieldClass *field_class = PURPLE_REQUEST_FIELD_CLASS(klass);
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ field_class->is_filled = purple_request_field_string_is_filled;
+
obj_class->finalize = purple_request_field_string_finalize;
obj_class->get_property = purple_request_field_string_get_property;
obj_class->set_property = purple_request_field_string_set_property;
@@ -237,14 +250,25 @@
purple_request_field_string_set_value(PurpleRequestFieldString *field,
const char *value)
{
+ gboolean before, after;
+
g_return_if_fail(PURPLE_IS_REQUEST_FIELD_STRING(field));
- if(!purple_strequal(field->value, value)) {
- g_free(field->value);
- field->value = g_strdup(value);
+ if(purple_strequal(field->value, value)) {
+ return;
+ }
- g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]);
+ before = purple_request_field_string_is_filled(PURPLE_REQUEST_FIELD(field));
+ g_free(field->value);
+ field->value = g_strdup(value);
+ after = purple_request_field_string_is_filled(PURPLE_REQUEST_FIELD(field));
+
+ g_object_freeze_notify(G_OBJECT(field));
+ g_object_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]);
+ if(before != after) {
+ g_object_notify(G_OBJECT(field), "filled");
}
+ g_object_thaw_notify(G_OBJECT(field));
}
void
--- a/libpurple/tests/meson.build Mon Mar 13 15:26:14 2023 -0500
+++ b/libpurple/tests/meson.build Tue Mar 14 00:42:47 2023 -0500
@@ -26,6 +26,7 @@
'protocol_xfer',
'purplepath',
'queued_output_stream',
+ 'request_field',
'str',
'tags',
'util',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_request_field.c Tue Mar 14 00:42:47 2023 -0500
@@ -0,0 +1,129 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_request_field_notify_filled_cb(G_GNUC_UNUSED GObject *obj,
+ G_GNUC_UNUSED GParamSpec *pspec,
+ gpointer data)
+{
+ gboolean *called = data;
+
+ *called = TRUE;
+}
+
+static void
+test_request_field_filled_string(void) {
+ PurpleRequestField *field = NULL;
+ gboolean called = FALSE;
+
+ field = purple_request_field_string_new("test-string", "Test string", NULL,
+ FALSE);
+ g_signal_connect(field, "notify::filled",
+ G_CALLBACK(test_request_field_notify_filled_cb), &called);
+ g_assert_false(purple_request_field_is_filled(field));
+
+ /* Passing same value should not trigger. */
+ called = FALSE;
+ purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+ NULL);
+ g_assert_false(called);
+ g_assert_false(purple_request_field_is_filled(field));
+
+ /* Passing an empty string should not trigger, as NULL and "" are
+ * considered the same. */
+ called = FALSE;
+ purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+ "");
+ g_assert_false(called);
+ g_assert_false(purple_request_field_is_filled(field));
+
+ /* Now that there's a change from empty to filled, notify should occur. */
+ called = FALSE;
+ purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+ "text");
+ g_assert_true(called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ /* Passing same value should not trigger. */
+ called = FALSE;
+ purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+ "text");
+ g_assert_false(called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ /* And then going back to empty should notify. */
+ called = FALSE;
+ purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
+ "");
+ g_assert_true(called);
+ g_assert_false(purple_request_field_is_filled(field));
+
+ g_object_unref(field);
+}
+
+static void
+test_request_field_filled_nonstring(void) {
+ /* Anything that's not a string should always be considered filled and
+ * never notify. */
+ PurpleRequestField *field = NULL;
+ gboolean called = FALSE;
+
+ field = purple_request_field_int_new("test-int", "Test int", 50, 0, 100);
+ g_signal_connect(field, "notify::filled",
+ G_CALLBACK(test_request_field_notify_filled_cb), &called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ called = FALSE;
+ purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 50);
+ g_assert_false(called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ called = FALSE;
+ purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 0);
+ g_assert_false(called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ called = FALSE;
+ purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field), 100);
+ g_assert_false(called);
+ g_assert_true(purple_request_field_is_filled(field));
+
+ g_object_unref(field);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/request-field/filled-string",
+ test_request_field_filled_string);
+ g_test_add_func("/request-field/filled-nonstring",
+ test_request_field_filled_nonstring);
+
+ return g_test_run();
+}