Commit 96e3677ce57ae4a6837a6afdedd2e5b2100eacd4

Authored by m-holger
Committed by GitHub
2 parents 6923f0d4 0ea709d4

Merge pull request #1639 from m-holger/srbv

Refactor `FormNode::setRadioButtonValue` (fixes #1449)
libqpdf/QPDFFormFieldObjectHelper.cc
... ... @@ -446,8 +446,8 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
446 446 void
447 447 FormNode::setV(QPDFObjectHandle value, bool need_appearances)
448 448 {
449   - Name name = value;
450 449 if (FT() == "/Btn") {
  450 + Name name = value;
451 451 if (isCheckbox()) {
452 452 if (!name) {
453 453 warn("ignoring attempt to set a checkbox field to a value whose type is not name");
... ... @@ -498,31 +498,30 @@ FormNode::setV(std::string const& utf8_value, bool need_appearances)
498 498 }
499 499  
500 500 void
501   -FormNode::setRadioButtonValue(QPDFObjectHandle name)
  501 +FormNode::setRadioButtonValue(Name const& name)
502 502 {
  503 + qpdf_expect(name);
503 504 // Set the value of a radio button field. This has the following specific behavior:
504   - // * If this is a radio button field that has a parent that is also a radio button field and has
505   - // no explicit /V, call itself on the parent
  505 + // * If this is a node without /Kids, assume this is a individual radio button widget and call
  506 + // itself on the parent
506 507 // * If this is a radio button field with children, set /V to the given value. Then, for each
507 508 // child, if the child has the specified value as one of its keys in the /N subdictionary of
508 509 // its /AP (i.e. its normal appearance stream dictionary), set /AS to name; otherwise, if /Off
509 510 // is a member, set /AS to /Off.
510   - // Note that we never turn on /NeedAppearances when setting a radio button field.
511   - QPDFObjectHandle parent = oh().getKey("/Parent");
512   - if (parent.isDictionary() && parent.getKey("/Parent").null()) {
513   - FormNode ph(parent);
514   - if (ph.isRadioButton()) {
515   - // This is most likely one of the individual buttons. Try calling on the parent.
516   - ph.setRadioButtonValue(name);
  511 + auto kids = Kids();
  512 + if (!kids) {
  513 + // This is most likely one of the individual buttons. Try calling on the parent.
  514 + auto parent = Parent();
  515 + if (parent.Kids()) {
  516 + parent.setRadioButtonValue(name);
517 517 return;
518 518 }
519 519 }
520   - auto kids = Kids();
521   - if (!(isRadioButton() && parent.null() && kids)) {
  520 + if (!isRadioButton() || !kids) {
522 521 warn("don't know how to set the value of this field as a radio button");
523 522 return;
524 523 }
525   - setFieldAttribute("/V", name);
  524 + replace("/V", name);
526 525 for (FormNode kid: kids) {
527 526 auto ap = kid.AP();
528 527 QPDFObjectHandle annot;
... ... @@ -542,7 +541,7 @@ FormNode::setRadioButtonValue(QPDFObjectHandle name)
542 541 warn("unable to set the value of this radio button");
543 542 continue;
544 543 }
545   - if (ap["/N"].contains(name.getName())) {
  544 + if (ap["/N"].contains(name.value())) {
546 545 annot.replace("/AS", name);
547 546 } else {
548 547 annot.replace("/AS", Name("/Off"));
... ...
libqpdf/qpdf/AcroForm.hh
... ... @@ -767,7 +767,14 @@ namespace qpdf::impl
767 767 return {qpdf() ? qpdf()->getRoot()["/AcroForm"][name] : null_oh};
768 768 }
769 769  
770   - void setRadioButtonValue(QPDFObjectHandle name);
  770 + /// @brief Sets the value of a radio button field.
  771 + ///
  772 + /// This method updates the value of a radio button field to the specified name.
  773 + /// It ensures that the radio button's state is consistent with the provided value.
  774 + ///
  775 + /// @param name The name of the radio button value to set. This corresponds to the
  776 + /// appearance state name of the selected radio button.
  777 + void setRadioButtonValue(Name const& name);
771 778 void setCheckBoxValue(bool value);
772 779 void generateTextAppearance(QPDFAnnotationObjectHelper&);
773 780  
... ...