1use crate::error::Result;
4use crate::forms::{
5 CheckBox, ComboBox, FieldOptions, FormField, ListBox, PushButton, RadioButton, TextField,
6 Widget,
7};
8use crate::objects::{Dictionary, Object, ObjectReference};
9use std::collections::HashMap;
10
11#[derive(Debug, Clone)]
13pub struct AcroForm {
14 pub fields: Vec<ObjectReference>,
16 pub need_appearances: bool,
18 pub sig_flags: Option<i32>,
20 pub co: Option<Vec<ObjectReference>>,
22 pub dr: Option<Dictionary>,
24 pub da: Option<String>,
26 pub q: Option<i32>,
28}
29
30impl AcroForm {
31 pub fn new() -> Self {
33 Self {
34 fields: Vec::new(),
35 need_appearances: true,
36 sig_flags: None,
37 co: None,
38 dr: None,
39 da: Some("/Helv 12 Tf 0 g".to_string()), q: None,
41 }
42 }
43
44 pub fn add_field(&mut self, field_ref: ObjectReference) {
46 self.fields.push(field_ref);
47 }
48
49 pub fn to_dict(&self) -> Dictionary {
51 let mut dict = Dictionary::new();
52
53 let fields: Vec<Object> = self.fields.iter().map(|r| Object::Reference(*r)).collect();
55 dict.set("Fields", Object::Array(fields));
56
57 dict.set("NeedAppearances", Object::Boolean(self.need_appearances));
59
60 if let Some(sig_flags) = self.sig_flags {
62 dict.set("SigFlags", Object::Integer(sig_flags as i64));
63 }
64
65 if let Some(ref co) = self.co {
67 let co_refs: Vec<Object> = co.iter().map(|r| Object::Reference(*r)).collect();
68 dict.set("CO", Object::Array(co_refs));
69 }
70
71 if let Some(ref dr) = self.dr {
73 dict.set("DR", Object::Dictionary(dr.clone()));
74 }
75
76 if let Some(ref da) = self.da {
78 dict.set("DA", Object::String(da.clone()));
79 }
80
81 if let Some(q) = self.q {
83 dict.set("Q", Object::Integer(q as i64));
84 }
85
86 dict
87 }
88}
89
90impl Default for AcroForm {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96#[derive(Debug, Clone)]
98pub struct FormData {
99 pub values: HashMap<String, String>,
101}
102
103impl FormData {
104 pub fn new() -> Self {
106 Self {
107 values: HashMap::new(),
108 }
109 }
110
111 pub fn set_value(&mut self, name: impl Into<String>, value: impl Into<String>) {
113 self.values.insert(name.into(), value.into());
114 }
115
116 pub fn get_value(&self, name: &str) -> Option<&str> {
118 self.values.get(name).map(|s| s.as_str())
119 }
120}
121
122impl Default for FormData {
123 fn default() -> Self {
124 Self::new()
125 }
126}
127
128#[derive(Debug)]
130pub struct FormManager {
131 fields: HashMap<String, FormField>,
133 field_refs: HashMap<String, ObjectReference>,
141 acro_form: AcroForm,
143 next_field_id: u32,
145}
146
147impl FormManager {
148 pub fn new() -> Self {
150 Self {
151 fields: HashMap::new(),
152 field_refs: HashMap::new(),
153 acro_form: AcroForm::new(),
154 next_field_id: 1,
155 }
156 }
157
158 pub fn add_text_field(
160 &mut self,
161 field: TextField,
162 widget: Widget,
163 options: Option<FieldOptions>,
164 ) -> Result<ObjectReference> {
165 let typed_da = field.default_appearance.clone();
170 let mut field_dict = field.to_dict();
171
172 if let Some(opts) = options {
174 if opts.flags.to_flags() != 0 {
175 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
176 }
177 if let Some(da) = opts.default_appearance {
178 field_dict.set("DA", Object::String(da));
179 }
180 if let Some(q) = opts.quadding {
181 field_dict.set("Q", Object::Integer(q as i64));
182 }
183 }
184
185 let field_name = field.name;
186 let mut form_field = FormField::new(field_dict);
187 form_field.default_appearance = typed_da;
188 form_field.add_widget(widget);
189
190 let obj_ref = ObjectReference::new(self.next_field_id, 0);
192 self.next_field_id += 1;
193 self.field_refs.insert(field_name.clone(), obj_ref);
194 self.fields.insert(field_name, form_field);
195 self.acro_form.add_field(obj_ref);
196
197 Ok(obj_ref)
198 }
199
200 pub fn add_combo_box(
202 &mut self,
203 combo: ComboBox,
204 widget: Widget,
205 options: Option<FieldOptions>,
206 ) -> Result<ObjectReference> {
207 let typed_da = combo.default_appearance.clone();
211 let mut field_dict = combo.to_dict();
212
213 if let Some(ref da) = typed_da {
217 field_dict.set("DA", Object::String(da.to_da_string()));
218 }
219
220 if let Some(opts) = options {
222 if opts.flags.to_flags() != 0 {
223 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
224 }
225 if let Some(da) = opts.default_appearance {
226 field_dict.set("DA", Object::String(da));
227 }
228 }
229
230 let field_name = combo.name;
231 let mut form_field = FormField::new(field_dict);
232 form_field.default_appearance = typed_da;
233 form_field.add_widget(widget);
234
235 let obj_ref = ObjectReference::new(self.next_field_id, 0);
237 self.next_field_id += 1;
238 self.field_refs.insert(field_name.clone(), obj_ref);
239 self.fields.insert(field_name, form_field);
240 self.acro_form.add_field(obj_ref);
241
242 Ok(obj_ref)
243 }
244
245 pub fn add_list_box(
247 &mut self,
248 listbox: ListBox,
249 widget: Widget,
250 options: Option<FieldOptions>,
251 ) -> Result<ObjectReference> {
252 let mut field_dict = listbox.to_dict();
253
254 if let Some(opts) = options {
256 if opts.flags.to_flags() != 0 {
257 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
258 }
259 if let Some(da) = opts.default_appearance {
260 field_dict.set("DA", Object::String(da));
261 }
262 }
263
264 let field_name = listbox.name;
265 let mut form_field = FormField::new(field_dict);
266 form_field.add_widget(widget);
267
268 let obj_ref = ObjectReference::new(self.next_field_id, 0);
270 self.next_field_id += 1;
271 self.field_refs.insert(field_name.clone(), obj_ref);
272 self.fields.insert(field_name, form_field);
273 self.acro_form.add_field(obj_ref);
274
275 Ok(obj_ref)
276 }
277
278 pub fn add_radio_button(
280 &mut self,
281 radio: RadioButton,
282 widgets: Option<Vec<Widget>>,
283 options: Option<FieldOptions>,
284 ) -> Result<ObjectReference> {
285 let mut field_dict = radio.to_dict();
286
287 if let Some(opts) = options {
289 if opts.flags.to_flags() != 0 {
290 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
291 }
292 if let Some(da) = opts.default_appearance {
293 field_dict.set("DA", Object::String(da));
294 }
295 }
296
297 let field_name = radio.name;
298 let mut form_field = FormField::new(field_dict);
299
300 if let Some(widgets) = widgets {
302 for widget in widgets {
303 form_field.add_widget(widget);
304 }
305 }
306
307 let obj_ref = ObjectReference::new(self.next_field_id, 0);
309 self.next_field_id += 1;
310 self.field_refs.insert(field_name.clone(), obj_ref);
311 self.fields.insert(field_name, form_field);
312 self.acro_form.add_field(obj_ref);
313
314 Ok(obj_ref)
315 }
316
317 pub fn add_checkbox(
319 &mut self,
320 checkbox: CheckBox,
321 widget: Widget,
322 options: Option<FieldOptions>,
323 ) -> Result<ObjectReference> {
324 let mut field_dict = checkbox.to_dict();
325
326 if let Some(opts) = options {
328 if opts.flags.to_flags() != 0 {
329 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
330 }
331 }
332
333 let field_name = checkbox.name;
334 let mut form_field = FormField::new(field_dict);
335 form_field.add_widget(widget);
336
337 let obj_ref = ObjectReference::new(self.next_field_id, 0);
339 self.next_field_id += 1;
340 self.field_refs.insert(field_name.clone(), obj_ref);
341 self.fields.insert(field_name, form_field);
342 self.acro_form.add_field(obj_ref);
343
344 Ok(obj_ref)
345 }
346
347 pub fn add_push_button(
349 &mut self,
350 button: PushButton,
351 widget: Widget,
352 options: Option<FieldOptions>,
353 ) -> Result<ObjectReference> {
354 let mut field_dict = button.to_dict();
355
356 if let Some(opts) = options {
358 if opts.flags.to_flags() != 0 {
359 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
360 }
361 }
362
363 let field_name = button.name;
364 let mut form_field = FormField::new(field_dict);
365 form_field.add_widget(widget);
366
367 let obj_ref = ObjectReference::new(self.next_field_id, 0);
369 self.next_field_id += 1;
370 self.field_refs.insert(field_name.clone(), obj_ref);
371 self.fields.insert(field_name, form_field);
372 self.acro_form.add_field(obj_ref);
373
374 Ok(obj_ref)
375 }
376
377 pub fn add_radio_buttons(
379 &mut self,
380 radio: RadioButton,
381 widgets: Vec<Widget>,
382 options: Option<FieldOptions>,
383 ) -> Result<ObjectReference> {
384 let mut field_dict = radio.to_dict();
385
386 if let Some(opts) = options {
388 if opts.flags.to_flags() != 0 {
389 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
390 }
391 }
392
393 let field_name = radio.name;
394 let mut form_field = FormField::new(field_dict);
395
396 for widget in widgets {
398 form_field.add_widget(widget);
399 }
400
401 let obj_ref = ObjectReference::new(self.next_field_id, 0);
403 self.next_field_id += 1;
404 self.field_refs.insert(field_name.clone(), obj_ref);
405 self.fields.insert(field_name, form_field);
406 self.acro_form.add_field(obj_ref);
407
408 Ok(obj_ref)
409 }
410
411 pub fn get_acro_form(&self) -> &AcroForm {
413 &self.acro_form
414 }
415
416 pub fn fields(&self) -> &HashMap<String, FormField> {
418 &self.fields
419 }
420
421 pub fn get_field(&self, name: &str) -> Option<&FormField> {
423 self.fields.get(name)
424 }
425
426 pub fn get_field_mut(&mut self, name: &str) -> Option<&mut FormField> {
434 self.fields.get_mut(name)
435 }
436
437 pub(crate) fn field_ref(&self, name: &str) -> Option<ObjectReference> {
452 self.field_refs.get(name).copied()
453 }
454
455 pub fn set_default_appearance(&mut self, da: impl Into<String>) {
457 self.acro_form.da = Some(da.into());
458 }
459
460 pub fn set_default_resources(&mut self, resources: Dictionary) {
462 self.acro_form.dr = Some(resources);
463 }
464}
465
466impl Default for FormManager {
467 fn default() -> Self {
468 Self::new()
469 }
470}
471
472impl FormManager {
473 pub fn field_count(&self) -> usize {
475 self.fields.len()
476 }
477
478 pub(crate) fn iter_fields_sorted(
507 &self,
508 ) -> impl Iterator<Item = (&String, &FormField, ObjectReference)> {
509 let mut keys: Vec<&String> = self.fields.keys().collect();
510 keys.sort();
511 keys.into_iter().map(move |k| {
512 let field = self
515 .fields
516 .get(k)
517 .expect("FormManager invariant: key from fields.keys() must resolve in fields");
518 let placeholder = *self.field_refs.get(k).expect(
519 "FormManager invariant: every field in `fields` must have an entry in \
520 `field_refs` — check add_*_field",
521 );
522 (k, field, placeholder)
523 })
524 }
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530 use crate::forms::FieldFlags;
531 use crate::geometry::{Point, Rectangle};
532
533 #[test]
534 fn test_acro_form() {
535 let mut acro_form = AcroForm::new();
536 acro_form.add_field(ObjectReference::new(1, 0));
537 acro_form.add_field(ObjectReference::new(2, 0));
538
539 let dict = acro_form.to_dict();
540 assert!(dict.get("Fields").is_some());
541 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
542 assert!(dict.get("DA").is_some());
543 }
544
545 #[test]
546 fn test_form_data() {
547 let mut form_data = FormData::new();
548 form_data.set_value("name", "John Doe");
549 form_data.set_value("email", "john@example.com");
550
551 assert_eq!(form_data.get_value("name"), Some("John Doe"));
552 assert_eq!(form_data.get_value("email"), Some("john@example.com"));
553 assert_eq!(form_data.get_value("phone"), None);
554 }
555
556 #[test]
557 fn test_form_manager_text_field() {
558 let mut manager = FormManager::new();
559
560 let field = TextField::new("username").with_default_value("guest");
561 let widget = Widget::new(Rectangle::new(
562 Point::new(100.0, 100.0),
563 Point::new(300.0, 120.0),
564 ));
565
566 let obj_ref = manager.add_text_field(field, widget, None).unwrap();
567 assert_eq!(obj_ref.number(), 1);
568 assert!(manager.get_field("username").is_some());
569 }
570
571 #[test]
572 fn test_form_manager_checkbox() {
573 let mut manager = FormManager::new();
574
575 let checkbox = CheckBox::new("agree").checked();
576 let widget = Widget::new(Rectangle::new(
577 Point::new(100.0, 100.0),
578 Point::new(115.0, 115.0),
579 ));
580
581 let obj_ref = manager.add_checkbox(checkbox, widget, None).unwrap();
582 assert_eq!(obj_ref.number(), 1);
583 assert!(manager.get_field("agree").is_some());
584 }
585
586 #[test]
596 fn iter_fields_sorted_is_non_fallible_and_ordered() {
597 let mut manager = FormManager::new();
598 let rect = Rectangle::new(Point::new(0.0, 0.0), Point::new(100.0, 20.0));
600 manager
601 .add_text_field(TextField::new("zeta"), Widget::new(rect), None)
602 .expect("add zeta");
603 manager
604 .add_text_field(TextField::new("alpha"), Widget::new(rect), None)
605 .expect("add alpha");
606 manager
607 .add_text_field(TextField::new("mu"), Widget::new(rect), None)
608 .expect("add mu");
609
610 let names: Vec<String> = manager
611 .iter_fields_sorted()
612 .map(|(name, _field, _placeholder)| name.clone())
613 .collect();
614 assert_eq!(
615 names,
616 vec!["alpha".to_string(), "mu".to_string(), "zeta".to_string()],
617 "iter_fields_sorted must yield keys in ASCII-lexicographic order"
618 );
619 }
620
621 #[test]
622 fn test_form_manager_multiple_fields() {
623 let mut manager = FormManager::new();
624
625 let text_field = TextField::new("name");
627 let text_widget = Widget::new(Rectangle::new(
628 Point::new(100.0, 200.0),
629 Point::new(300.0, 220.0),
630 ));
631 manager
632 .add_text_field(text_field, text_widget, None)
633 .unwrap();
634
635 let checkbox = CheckBox::new("subscribe");
637 let check_widget = Widget::new(Rectangle::new(
638 Point::new(100.0, 150.0),
639 Point::new(115.0, 165.0),
640 ));
641 manager.add_checkbox(checkbox, check_widget, None).unwrap();
642
643 assert_eq!(manager.fields().len(), 2);
644 assert!(manager.get_field("name").is_some());
645 assert!(manager.get_field("subscribe").is_some());
646 }
647
648 #[test]
649 fn test_acro_form_comprehensive() {
650 let mut acro_form = AcroForm::new();
651
652 assert_eq!(acro_form.fields.len(), 0);
654 assert!(acro_form.need_appearances);
655 assert!(acro_form.sig_flags.is_none());
656 assert!(acro_form.co.is_none());
657 assert!(acro_form.dr.is_none());
658 assert!(acro_form.da.is_some());
659 assert!(acro_form.q.is_none());
660
661 for i in 1..=5 {
663 acro_form.add_field(ObjectReference::new(i, 0));
664 }
665 assert_eq!(acro_form.fields.len(), 5);
666
667 acro_form.sig_flags = Some(3);
669 acro_form.co = Some(vec![ObjectReference::new(1, 0), ObjectReference::new(2, 0)]);
670 acro_form.q = Some(2); let mut dr = Dictionary::new();
673 dr.set("Font", Object::String("Helvetica".to_string()));
674 acro_form.dr = Some(dr);
675
676 let dict = acro_form.to_dict();
678
679 if let Some(Object::Array(fields)) = dict.get("Fields") {
681 assert_eq!(fields.len(), 5);
682 for (i, field) in fields.iter().enumerate() {
683 assert_eq!(
684 *field,
685 Object::Reference(ObjectReference::new((i + 1) as u32, 0))
686 );
687 }
688 } else {
689 panic!("Expected Fields array");
690 }
691
692 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
694 assert_eq!(dict.get("SigFlags"), Some(&Object::Integer(3)));
695 assert_eq!(dict.get("Q"), Some(&Object::Integer(2)));
696 assert!(dict.get("CO").is_some());
697 assert!(dict.get("DR").is_some());
698 assert!(dict.get("DA").is_some());
699 }
700
701 #[test]
702 fn test_acro_form_default() {
703 let acro_form = AcroForm::default();
704 let default_form = AcroForm::new();
705
706 assert_eq!(acro_form.fields.len(), default_form.fields.len());
707 assert_eq!(acro_form.need_appearances, default_form.need_appearances);
708 assert_eq!(acro_form.sig_flags, default_form.sig_flags);
709 assert_eq!(acro_form.da, default_form.da);
710 }
711
712 #[test]
713 fn test_acro_form_debug_clone() {
714 let mut acro_form = AcroForm::new();
715 acro_form.add_field(ObjectReference::new(1, 0));
716 acro_form.sig_flags = Some(1);
717
718 let debug_str = format!("{acro_form:?}");
719 assert!(debug_str.contains("AcroForm"));
720
721 let cloned = acro_form.clone();
722 assert_eq!(acro_form.fields, cloned.fields);
723 assert_eq!(acro_form.sig_flags, cloned.sig_flags);
724 assert_eq!(acro_form.need_appearances, cloned.need_appearances);
725 }
726
727 #[test]
728 fn test_form_data_comprehensive() {
729 let mut form_data = FormData::new();
730
731 assert_eq!(form_data.values.len(), 0);
733 assert_eq!(form_data.get_value("any"), None);
734
735 form_data.set_value("string_literal", "test");
737 form_data.set_value(String::from("string_owned"), "test2");
738 form_data.set_value("number", "42");
739 form_data.set_value("empty", "");
740 form_data.set_value("unicode", "café ñoño 你好");
741
742 assert_eq!(form_data.values.len(), 5);
743 assert_eq!(form_data.get_value("string_literal"), Some("test"));
744 assert_eq!(form_data.get_value("string_owned"), Some("test2"));
745 assert_eq!(form_data.get_value("number"), Some("42"));
746 assert_eq!(form_data.get_value("empty"), Some(""));
747 assert_eq!(form_data.get_value("unicode"), Some("café ñoño 你好"));
748
749 form_data.set_value("string_literal", "overwritten");
751 assert_eq!(form_data.get_value("string_literal"), Some("overwritten"));
752 assert_eq!(form_data.values.len(), 5); form_data.set_value("Test", "uppercase");
756 form_data.set_value("test", "lowercase");
757 assert_eq!(form_data.get_value("Test"), Some("uppercase"));
758 assert_eq!(form_data.get_value("test"), Some("lowercase"));
759 assert_eq!(form_data.values.len(), 7);
760 }
761
762 #[test]
763 fn test_form_data_edge_cases() {
764 let mut form_data = FormData::new();
765
766 form_data.set_value("", "empty_name");
768 assert_eq!(form_data.get_value(""), Some("empty_name"));
769
770 let long_name = "a".repeat(1000);
772 let long_value = "b".repeat(2000);
773 form_data.set_value(&long_name, &long_value);
774 assert_eq!(form_data.get_value(&long_name), Some(long_value.as_str()));
775
776 form_data.set_value("field/with/slashes", "value1");
778 form_data.set_value("field with spaces", "value2");
779 form_data.set_value("field.with.dots", "value3");
780 form_data.set_value("field-with-dashes", "value4");
781 form_data.set_value("field_with_underscores", "value5");
782
783 assert_eq!(form_data.get_value("field/with/slashes"), Some("value1"));
784 assert_eq!(form_data.get_value("field with spaces"), Some("value2"));
785 assert_eq!(form_data.get_value("field.with.dots"), Some("value3"));
786 assert_eq!(form_data.get_value("field-with-dashes"), Some("value4"));
787 assert_eq!(
788 form_data.get_value("field_with_underscores"),
789 Some("value5")
790 );
791 }
792
793 #[test]
794 fn test_form_data_default_debug_clone() {
795 let form_data = FormData::default();
796 assert_eq!(form_data.values.len(), 0);
797
798 let default_form = FormData::new();
799 assert_eq!(form_data.values.len(), default_form.values.len());
800
801 let debug_str = format!("{form_data:?}");
802 assert!(debug_str.contains("FormData"));
803
804 let cloned = form_data.clone();
805 assert_eq!(form_data.values.len(), cloned.values.len());
806 }
807
808 #[test]
809 fn test_form_manager_comprehensive() {
810 let mut manager = FormManager::new();
811
812 assert_eq!(manager.field_count(), 0);
814 assert_eq!(manager.fields().len(), 0);
815 assert!(manager.get_field("nonexistent").is_none());
816
817 let acroform = manager.get_acro_form();
818 assert_eq!(acroform.fields.len(), 0);
819 assert!(acroform.need_appearances);
820
821 let field1 = TextField::new("field1");
823 let widget1 = Widget::new(Rectangle::new(
824 Point::new(0.0, 0.0),
825 Point::new(100.0, 20.0),
826 ));
827 let ref1 = manager.add_text_field(field1, widget1, None).unwrap();
828 assert_eq!(ref1.number(), 1);
829
830 let field2 = TextField::new("field2");
831 let widget2 = Widget::new(Rectangle::new(
832 Point::new(0.0, 30.0),
833 Point::new(100.0, 50.0),
834 ));
835 let ref2 = manager.add_text_field(field2, widget2, None).unwrap();
836 assert_eq!(ref2.number(), 2);
837
838 let field3 = TextField::new("field3");
839 let widget3 = Widget::new(Rectangle::new(
840 Point::new(0.0, 60.0),
841 Point::new(100.0, 80.0),
842 ));
843 let ref3 = manager.add_text_field(field3, widget3, None).unwrap();
844 assert_eq!(ref3.number(), 3);
845
846 assert_eq!(manager.field_count(), 3);
847 assert_eq!(manager.get_acro_form().fields.len(), 3);
848 }
849
850 #[test]
851 fn test_form_manager_push_button() {
852 let mut manager = FormManager::new();
853
854 let button = PushButton::new("submit").with_caption("Submit");
855 let widget = Widget::new(Rectangle::new(
856 Point::new(200.0, 100.0),
857 Point::new(280.0, 130.0),
858 ));
859
860 let obj_ref = manager.add_push_button(button, widget, None).unwrap();
861 assert_eq!(obj_ref.number(), 1);
862 assert!(manager.get_field("submit").is_some());
863
864 let form_field = manager.get_field("submit").unwrap();
865 let dict = &form_field.field_dict;
866 assert_eq!(dict.get("T"), Some(&Object::String("submit".to_string())));
867 assert_eq!(dict.get("FT"), Some(&Object::Name("Btn".to_string())));
868 }
869
870 #[test]
871 fn test_form_manager_radio_buttons() {
872 let mut manager = FormManager::new();
873
874 let radio = RadioButton::new("gender")
875 .add_option("M", "Male")
876 .add_option("F", "Female")
877 .with_selected(0);
878
879 let widgets = vec![
880 Widget::new(Rectangle::new(
881 Point::new(100.0, 100.0),
882 Point::new(115.0, 115.0),
883 )),
884 Widget::new(Rectangle::new(
885 Point::new(150.0, 100.0),
886 Point::new(165.0, 115.0),
887 )),
888 ];
889
890 let obj_ref = manager.add_radio_buttons(radio, widgets, None).unwrap();
891 assert_eq!(obj_ref.number(), 1);
892 assert!(manager.get_field("gender").is_some());
893
894 let form_field = manager.get_field("gender").unwrap();
895 assert_eq!(form_field.widgets.len(), 2);
896
897 let dict = &form_field.field_dict;
898 assert_eq!(dict.get("T"), Some(&Object::String("gender".to_string())));
899 assert_eq!(dict.get("V"), Some(&Object::Name("M".to_string())));
900 }
901
902 #[test]
903 fn test_form_manager_list_box() {
904 let mut manager = FormManager::new();
905
906 let listbox = ListBox::new("languages")
907 .add_option("en", "English")
908 .add_option("es", "Spanish")
909 .add_option("fr", "French")
910 .multi_select()
911 .with_selected(vec![0, 2]);
912
913 let widget = Widget::new(Rectangle::new(
914 Point::new(100.0, 100.0),
915 Point::new(200.0, 150.0),
916 ));
917
918 let obj_ref = manager.add_list_box(listbox, widget, None).unwrap();
919 assert_eq!(obj_ref.number(), 1);
920 assert!(manager.get_field("languages").is_some());
921
922 let form_field = manager.get_field("languages").unwrap();
923 let dict = &form_field.field_dict;
924 assert_eq!(
925 dict.get("T"),
926 Some(&Object::String("languages".to_string()))
927 );
928 assert_eq!(dict.get("FT"), Some(&Object::Name("Ch".to_string())));
929 }
930
931 #[test]
932 fn test_form_manager_combo_box() {
933 let mut manager = FormManager::new();
934
935 let combo = ComboBox::new("country")
936 .add_option("US", "United States")
937 .add_option("CA", "Canada")
938 .editable()
939 .with_value("US");
940
941 let widget = Widget::new(Rectangle::new(
942 Point::new(100.0, 100.0),
943 Point::new(300.0, 120.0),
944 ));
945
946 let obj_ref = manager.add_combo_box(combo, widget, None).unwrap();
947 assert_eq!(obj_ref.number(), 1);
948 assert!(manager.get_field("country").is_some());
949
950 let form_field = manager.get_field("country").unwrap();
951 let dict = &form_field.field_dict;
952 assert_eq!(dict.get("T"), Some(&Object::String("country".to_string())));
953 assert_eq!(dict.get("V"), Some(&Object::String("US".to_string())));
954 }
955
956 #[test]
957 fn test_form_manager_with_field_options() {
958 let mut manager = FormManager::new();
959
960 let options = FieldOptions {
961 flags: FieldFlags {
962 read_only: true,
963 required: true,
964 no_export: false,
965 },
966 default_appearance: Some("/Times-Roman 12 Tf 0 g".to_string()),
967 quadding: Some(1), };
969
970 let field = TextField::new("readonly_field").with_value("Read Only");
971 let widget = Widget::new(Rectangle::new(
972 Point::new(50.0, 50.0),
973 Point::new(250.0, 70.0),
974 ));
975
976 manager
977 .add_text_field(field, widget, Some(options))
978 .unwrap();
979
980 let form_field = manager.get_field("readonly_field").unwrap();
981 let dict = &form_field.field_dict;
982
983 if let Some(Object::Integer(flags)) = dict.get("Ff") {
985 assert_ne!(*flags & (1 << 0), 0); assert_ne!(*flags & (1 << 1), 0); assert_eq!(*flags & (1 << 2), 0); } else {
989 panic!("Expected Ff field");
990 }
991
992 assert_eq!(
994 dict.get("DA"),
995 Some(&Object::String("/Times-Roman 12 Tf 0 g".to_string()))
996 );
997 assert_eq!(dict.get("Q"), Some(&Object::Integer(1)));
998 }
999
1000 #[test]
1001 fn test_form_manager_appearance_resources() {
1002 let mut manager = FormManager::new();
1003
1004 manager.set_default_appearance("/Courier 10 Tf 0.5 g");
1006 let acroform = manager.get_acro_form();
1007 assert_eq!(acroform.da, Some("/Courier 10 Tf 0.5 g".to_string()));
1008
1009 let mut resources = Dictionary::new();
1011 let mut font_dict = Dictionary::new();
1012 font_dict.set("F1", Object::String("Helvetica".to_string()));
1013 font_dict.set("F2", Object::String("Times-Roman".to_string()));
1014 resources.set("Font", Object::Dictionary(font_dict));
1015
1016 let mut color_dict = Dictionary::new();
1017 color_dict.set(
1018 "Red",
1019 Object::Array(vec![
1020 Object::Real(1.0),
1021 Object::Real(0.0),
1022 Object::Real(0.0),
1023 ]),
1024 );
1025 resources.set("ColorSpace", Object::Dictionary(color_dict));
1026
1027 manager.set_default_resources(resources);
1028
1029 let acroform = manager.get_acro_form();
1030 assert!(acroform.dr.is_some());
1031
1032 let dict = acroform.to_dict();
1033 assert_eq!(
1034 dict.get("DA"),
1035 Some(&Object::String("/Courier 10 Tf 0.5 g".to_string()))
1036 );
1037
1038 if let Some(Object::Dictionary(dr_dict)) = dict.get("DR") {
1039 assert!(dr_dict.get("Font").is_some());
1040 assert!(dr_dict.get("ColorSpace").is_some());
1041 } else {
1042 panic!("Expected DR dictionary");
1043 }
1044 }
1045
1046 #[test]
1047 fn test_form_manager_mixed_field_types() {
1048 let mut manager = FormManager::new();
1049
1050 let text_field = TextField::new("name").with_value("John");
1052 let text_widget = Widget::new(Rectangle::new(
1053 Point::new(10.0, 100.0),
1054 Point::new(210.0, 120.0),
1055 ));
1056 manager
1057 .add_text_field(text_field, text_widget, None)
1058 .unwrap();
1059
1060 let checkbox = CheckBox::new("agree").checked();
1061 let check_widget = Widget::new(Rectangle::new(
1062 Point::new(10.0, 80.0),
1063 Point::new(25.0, 95.0),
1064 ));
1065 manager.add_checkbox(checkbox, check_widget, None).unwrap();
1066
1067 let button = PushButton::new("submit");
1068 let button_widget = Widget::new(Rectangle::new(
1069 Point::new(10.0, 50.0),
1070 Point::new(80.0, 75.0),
1071 ));
1072 manager
1073 .add_push_button(button, button_widget, None)
1074 .unwrap();
1075
1076 let radio = RadioButton::new("choice").add_option("A", "Option A");
1077 let radio_widgets = vec![Widget::new(Rectangle::new(
1078 Point::new(10.0, 30.0),
1079 Point::new(25.0, 45.0),
1080 ))];
1081 manager
1082 .add_radio_buttons(radio, radio_widgets, None)
1083 .unwrap();
1084
1085 let listbox = ListBox::new("items").add_option("1", "Item 1");
1086 let list_widget = Widget::new(Rectangle::new(
1087 Point::new(10.0, 10.0),
1088 Point::new(110.0, 25.0),
1089 ));
1090 manager.add_list_box(listbox, list_widget, None).unwrap();
1091
1092 let combo = ComboBox::new("selection").add_option("opt", "Option");
1093 let combo_widget = Widget::new(Rectangle::new(
1094 Point::new(120.0, 10.0),
1095 Point::new(220.0, 25.0),
1096 ));
1097 manager.add_combo_box(combo, combo_widget, None).unwrap();
1098
1099 assert_eq!(manager.field_count(), 6);
1101 assert!(manager.get_field("name").is_some());
1102 assert!(manager.get_field("agree").is_some());
1103 assert!(manager.get_field("submit").is_some());
1104 assert!(manager.get_field("choice").is_some());
1105 assert!(manager.get_field("items").is_some());
1106 assert!(manager.get_field("selection").is_some());
1107
1108 let acroform = manager.get_acro_form();
1110 assert_eq!(acroform.fields.len(), 6);
1111
1112 for (i, field_ref) in acroform.fields.iter().enumerate() {
1114 assert_eq!(field_ref.number(), (i + 1) as u32);
1115 assert_eq!(field_ref.generation(), 0);
1116 }
1117 }
1118
1119 #[test]
1120 fn test_form_manager_debug_default() {
1121 let manager = FormManager::new();
1122 let debug_str = format!("{manager:?}");
1123 assert!(debug_str.contains("FormManager"));
1124
1125 let default_manager = FormManager::default();
1126 assert_eq!(manager.field_count(), default_manager.field_count());
1127 }
1128
1129 #[test]
1130 fn test_form_manager_error_scenarios() {
1131 let mut manager = FormManager::new();
1132
1133 let empty_field = TextField::new("");
1135 let widget = Widget::new(Rectangle::new(
1136 Point::new(0.0, 0.0),
1137 Point::new(100.0, 20.0),
1138 ));
1139 let result = manager.add_text_field(empty_field, widget, None);
1140 assert!(result.is_ok());
1141 assert!(manager.get_field("").is_some());
1142
1143 let field1 = TextField::new("duplicate");
1145 let widget1 = Widget::new(Rectangle::new(
1146 Point::new(0.0, 0.0),
1147 Point::new(100.0, 20.0),
1148 ));
1149 manager.add_text_field(field1, widget1, None).unwrap();
1150
1151 let field2 = TextField::new("duplicate");
1152 let widget2 = Widget::new(Rectangle::new(
1153 Point::new(0.0, 30.0),
1154 Point::new(100.0, 50.0),
1155 ));
1156 manager.add_text_field(field2, widget2, None).unwrap();
1157
1158 assert_eq!(manager.field_count(), 2); assert!(manager.get_field("duplicate").is_some());
1161 }
1162
1163 #[test]
1164 fn test_acro_form_calculation_order() {
1165 let mut acro_form = AcroForm::new();
1166
1167 let calc_order = vec![
1169 ObjectReference::new(3, 0),
1170 ObjectReference::new(1, 0),
1171 ObjectReference::new(2, 0),
1172 ];
1173 acro_form.co = Some(calc_order);
1174
1175 let dict = acro_form.to_dict();
1176
1177 if let Some(Object::Array(co_array)) = dict.get("CO") {
1178 assert_eq!(co_array.len(), 3);
1179 assert_eq!(co_array[0], Object::Reference(ObjectReference::new(3, 0)));
1180 assert_eq!(co_array[1], Object::Reference(ObjectReference::new(1, 0)));
1181 assert_eq!(co_array[2], Object::Reference(ObjectReference::new(2, 0)));
1182 } else {
1183 panic!("Expected CO array");
1184 }
1185 }
1186
1187 #[test]
1188 fn test_acro_form_without_optional_fields() {
1189 let acro_form = AcroForm::new();
1190 let dict = acro_form.to_dict();
1191
1192 assert!(dict.get("SigFlags").is_none());
1194 assert!(dict.get("CO").is_none());
1195 assert!(dict.get("DR").is_none());
1196 assert!(dict.get("Q").is_none());
1197
1198 assert!(dict.get("Fields").is_some());
1200 assert!(dict.get("NeedAppearances").is_some());
1201 assert!(dict.get("DA").is_some());
1202 }
1203}