summaryrefslogtreecommitdiff
path: root/libpurple
diff options
context:
space:
mode:
authorElliott Sales de Andrade <quantum.analyst@gmail.com>2023-03-14 00:42:47 -0500
committerElliott Sales de Andrade <quantum.analyst@gmail.com>2023-03-14 00:42:47 -0500
commit6ace7e4ef5e70584ecebe53c200d6c5732e48ed6 (patch)
tree149777ee249e8450078e9d57500803181ae5afc6 /libpurple
parent1f272fcf80b5254a4e60561df36678c385319ee5 (diff)
downloadpidgin-6ace7e4ef5e70584ecebe53c200d6c5732e48ed6.tar.gz
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/
Diffstat (limited to 'libpurple')
-rw-r--r--libpurple/purplerequestfield.c30
-rw-r--r--libpurple/purplerequestfield.h7
-rw-r--r--libpurple/request/purplerequestfieldstring.c32
-rw-r--r--libpurple/tests/meson.build1
-rw-r--r--libpurple/tests/test_request_field.c129
5 files changed, 189 insertions, 10 deletions
diff --git a/libpurple/purplerequestfield.c b/libpurple/purplerequestfield.c
index 5c6f1611af..3b9bd233d8 100644
--- a/libpurple/purplerequestfield.c
+++ b/libpurple/purplerequestfield.c
@@ -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 @@ enum {
PROP_TYPE_HINT,
PROP_TOOLTIP,
PROP_REQUIRED,
+ PROP_FILLED,
PROP_IS_VALIDATABLE,
N_PROPERTIES,
};
@@ -107,6 +107,10 @@ purple_request_field_get_property(GObject *obj, guint param_id, GValue *value,
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 @@ purple_request_field_class_init(PurpleRequestFieldClass *klass) {
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 @@ purple_request_field_is_required(PurpleRequestField *field) {
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
diff --git a/libpurple/purplerequestfield.h b/libpurple/purplerequestfield.h
index b87f8889e4..b81aa6e642 100644
--- a/libpurple/purplerequestfield.h
+++ b/libpurple/purplerequestfield.h
@@ -53,6 +53,7 @@ struct _PurpleRequestFieldClass {
GObjectClass parent_class;
/*< public >*/
+ gboolean (*is_filled)(PurpleRequestField *field);
/*< private >*/
gpointer reserved[4];
@@ -193,7 +194,11 @@ gboolean purple_request_field_is_required(PurpleRequestField *field);
* 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.
*/
diff --git a/libpurple/request/purplerequestfieldstring.c b/libpurple/request/purplerequestfieldstring.c
index 7779ce3261..5f41ec3726 100644
--- a/libpurple/request/purplerequestfieldstring.c
+++ b/libpurple/request/purplerequestfieldstring.c
@@ -57,6 +57,16 @@ purple_request_field_string_set_multiline(PurpleRequestFieldString *field,
}
/******************************************************************************
+ * 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 @@ purple_request_field_string_init(G_GNUC_UNUSED PurpleRequestFieldString *field)
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 @@ void
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;
+ }
+
+ 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_notify_by_pspec(G_OBJECT(field), properties[PROP_VALUE]);
+ 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
diff --git a/libpurple/tests/meson.build b/libpurple/tests/meson.build
index 0f18916706..c922b80c3c 100644
--- a/libpurple/tests/meson.build
+++ b/libpurple/tests/meson.build
@@ -26,6 +26,7 @@ PROGS = [
'protocol_xfer',
'purplepath',
'queued_output_stream',
+ 'request_field',
'str',
'tags',
'util',
diff --git a/libpurple/tests/test_request_field.c b/libpurple/tests/test_request_field.c
new file mode 100644
index 0000000000..a15d3e12b6
--- /dev/null
+++ b/libpurple/tests/test_request_field.c
@@ -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();
+}