summaryrefslogtreecommitdiff
path: root/pdf/pdf_form.c
diff options
context:
space:
mode:
authorPaul Gardiner <paul@glidos.net>2012-06-25 15:11:40 +0100
committerPaul Gardiner <paul@glidos.net>2012-06-25 15:11:40 +0100
commitf35c11d2852e8878f977145e3d2fd20f29eaf485 (patch)
treed13279fec888773b0a30bb208de5a2209220c3f0 /pdf/pdf_form.c
parent56895fa7c1ecc5e3f1e47e5a3e4234755d573262 (diff)
downloadmupdf-f35c11d2852e8878f977145e3d2fd20f29eaf485.tar.xz
Forms: handle clicking on one of a group of like-named check boxes
All of the group are updated which can make them act like radio buttons in the case that all have different "on" values
Diffstat (limited to 'pdf/pdf_form.c')
-rw-r--r--pdf/pdf_form.c112
1 files changed, 93 insertions, 19 deletions
diff --git a/pdf/pdf_form.c b/pdf/pdf_form.c
index 0971edd1..e0dc0f06 100644
--- a/pdf/pdf_form.c
+++ b/pdf/pdf_form.c
@@ -212,6 +212,16 @@ static int get_field_type(pdf_document *doc, pdf_obj *obj)
return -1;
}
+/* Find the point in a field hierarchy where all descendents
+ * share the same name */
+static pdf_obj *find_head_of_field_group(pdf_obj *obj)
+{
+ if (obj == NULL || pdf_dict_gets(obj, "T"))
+ return obj;
+ else
+ return find_head_of_field_group(pdf_dict_gets(obj, "Parent"));
+}
+
static void pdf_field_mark_dirty(fz_context *ctx, pdf_obj *field)
{
if (!pdf_dict_gets(field, "Dirty"))
@@ -1054,11 +1064,13 @@ static int get_matrix(pdf_document *doc, pdf_xobject *form, int q, fz_matrix *mt
static void update_text_field_value(fz_context *ctx, pdf_obj *obj, char *text)
{
pdf_obj *sobj = NULL;
+ pdf_obj *grp;
- /* obj is an annotation. If it isn't also a field then the parent is
- * the associated field */
- if (!pdf_dict_gets(obj, "FT"))
- obj = pdf_dict_gets(obj, "Parent");
+ /* All fields of the same name should be updated, so
+ * set the value at the head of the group */
+ grp = find_head_of_field_group(obj);
+ if (grp)
+ obj = grp;
fz_var(sobj);
fz_try(ctx)
@@ -1492,6 +1504,52 @@ static void check_off(fz_context *ctx, pdf_obj *obj)
}
}
+static void set_check(fz_context *ctx, pdf_obj *chk, char *name)
+{
+ pdf_obj *n = pdf_dict_getp(chk, "AP/N");
+ pdf_obj *val = NULL;
+
+ fz_var(val);
+ fz_try(ctx)
+ {
+ /* If name is a possible value of this check
+ * box then use it, otherwise use "Off" */
+ if (pdf_dict_gets(n, name))
+ val = fz_new_name(ctx, name);
+ else
+ val = fz_new_name(ctx, "Off");
+
+ pdf_dict_puts(chk, "AS", val);
+ }
+ fz_always(ctx)
+ {
+ pdf_drop_obj(val);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
+/* Set the values of all fields in a group defined by a node
+ * in the hierarchy */
+static void set_check_grp(fz_context *ctx, pdf_obj *grp, char *val)
+{
+ pdf_obj *kids = pdf_dict_gets(grp, "Kids");
+
+ if (kids == NULL)
+ {
+ set_check(ctx, grp, val);
+ }
+ else
+ {
+ int i, n = pdf_array_len(kids);
+
+ for (i = 0; i < n; i++)
+ set_check_grp(ctx, pdf_array_get(kids, i), val);
+ }
+}
+
static void toggle_check_box(pdf_document *doc, pdf_obj *obj)
{
fz_context *ctx = doc->ctx;
@@ -1507,10 +1565,26 @@ static void toggle_check_box(pdf_document *doc, pdf_obj *obj)
}
else
{
- pdf_obj *ap, *n, *key;
+ pdf_obj *n, *key = NULL;
int len, i;
- /* For radio buttons, first turn off all buttons in the group */
+ n = pdf_dict_getp(obj, "AP/N");
+
+ /* Look for a key that isn't "Off" */
+ len = pdf_dict_len(n);
+ for (i = 0; i < len; i++)
+ {
+ key = pdf_dict_get_key(n, i);
+ if (pdf_is_name(key) && strcmp(pdf_to_name(key), "Off"))
+ break;
+ }
+
+ /* If we found no alternative value to Off then we have no value to use */
+ if (!key)
+ return;
+
+ /* For radio buttons, first turn off all buttons in the group and
+ * then set the one that was clicked */
if ((ff & (Ff_Pushbutton|Ff_Radio)) == Ff_Radio)
{
pdf_obj *kids = pdf_dict_getp(obj, "Parent/Kids");
@@ -1518,21 +1592,21 @@ static void toggle_check_box(pdf_document *doc, pdf_obj *obj)
for (i = 0; i < n; i++)
check_off(ctx, pdf_array_get(kids, i));
- }
-
- ap = pdf_dict_gets(obj, "AP");
- n = pdf_dict_gets(ap, "N");
- /* Look for a key that isn't "Off" */
- len = pdf_dict_len(n);
- for (i = 0; i < len; i++)
+ pdf_dict_puts(obj, "AS", key);
+ }
+ else
{
- key = pdf_dict_get_key(n, i);
- if (pdf_is_name(key) && strcmp(pdf_to_name(key), "Off"))
- {
- pdf_dict_puts(obj, "AS", key);
- break;
- }
+ /* For check boxes, locate the node of the field hierarchy below
+ * which all fields share a name with the clicked one, and set
+ * all to the same value. This may cause the group to act like
+ * radio buttons, if each have distinct "On" values */
+ pdf_obj *grp = find_head_of_field_group(obj);
+
+ if (grp)
+ set_check_grp(doc->ctx, grp, pdf_to_name(key));
+ else
+ set_check(doc->ctx, obj, pdf_to_name(key));
}
}