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 mut field_dict = combo.to_dict();
208
209 if let Some(opts) = options {
211 if opts.flags.to_flags() != 0 {
212 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
213 }
214 if let Some(da) = opts.default_appearance {
215 field_dict.set("DA", Object::String(da));
216 }
217 }
218
219 let field_name = combo.name;
220 let mut form_field = FormField::new(field_dict);
221 form_field.add_widget(widget);
222
223 let obj_ref = ObjectReference::new(self.next_field_id, 0);
225 self.next_field_id += 1;
226 self.field_refs.insert(field_name.clone(), obj_ref);
227 self.fields.insert(field_name, form_field);
228 self.acro_form.add_field(obj_ref);
229
230 Ok(obj_ref)
231 }
232
233 pub fn add_list_box(
235 &mut self,
236 listbox: ListBox,
237 widget: Widget,
238 options: Option<FieldOptions>,
239 ) -> Result<ObjectReference> {
240 let mut field_dict = listbox.to_dict();
241
242 if let Some(opts) = options {
244 if opts.flags.to_flags() != 0 {
245 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
246 }
247 if let Some(da) = opts.default_appearance {
248 field_dict.set("DA", Object::String(da));
249 }
250 }
251
252 let field_name = listbox.name;
253 let mut form_field = FormField::new(field_dict);
254 form_field.add_widget(widget);
255
256 let obj_ref = ObjectReference::new(self.next_field_id, 0);
258 self.next_field_id += 1;
259 self.field_refs.insert(field_name.clone(), obj_ref);
260 self.fields.insert(field_name, form_field);
261 self.acro_form.add_field(obj_ref);
262
263 Ok(obj_ref)
264 }
265
266 pub fn add_radio_button(
268 &mut self,
269 radio: RadioButton,
270 widgets: Option<Vec<Widget>>,
271 options: Option<FieldOptions>,
272 ) -> Result<ObjectReference> {
273 let mut field_dict = radio.to_dict();
274
275 if let Some(opts) = options {
277 if opts.flags.to_flags() != 0 {
278 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
279 }
280 if let Some(da) = opts.default_appearance {
281 field_dict.set("DA", Object::String(da));
282 }
283 }
284
285 let field_name = radio.name;
286 let mut form_field = FormField::new(field_dict);
287
288 if let Some(widgets) = widgets {
290 for widget in widgets {
291 form_field.add_widget(widget);
292 }
293 }
294
295 let obj_ref = ObjectReference::new(self.next_field_id, 0);
297 self.next_field_id += 1;
298 self.field_refs.insert(field_name.clone(), obj_ref);
299 self.fields.insert(field_name, form_field);
300 self.acro_form.add_field(obj_ref);
301
302 Ok(obj_ref)
303 }
304
305 pub fn add_checkbox(
307 &mut self,
308 checkbox: CheckBox,
309 widget: Widget,
310 options: Option<FieldOptions>,
311 ) -> Result<ObjectReference> {
312 let mut field_dict = checkbox.to_dict();
313
314 if let Some(opts) = options {
316 if opts.flags.to_flags() != 0 {
317 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
318 }
319 }
320
321 let field_name = checkbox.name;
322 let mut form_field = FormField::new(field_dict);
323 form_field.add_widget(widget);
324
325 let obj_ref = ObjectReference::new(self.next_field_id, 0);
327 self.next_field_id += 1;
328 self.field_refs.insert(field_name.clone(), obj_ref);
329 self.fields.insert(field_name, form_field);
330 self.acro_form.add_field(obj_ref);
331
332 Ok(obj_ref)
333 }
334
335 pub fn add_push_button(
337 &mut self,
338 button: PushButton,
339 widget: Widget,
340 options: Option<FieldOptions>,
341 ) -> Result<ObjectReference> {
342 let mut field_dict = button.to_dict();
343
344 if let Some(opts) = options {
346 if opts.flags.to_flags() != 0 {
347 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
348 }
349 }
350
351 let field_name = button.name;
352 let mut form_field = FormField::new(field_dict);
353 form_field.add_widget(widget);
354
355 let obj_ref = ObjectReference::new(self.next_field_id, 0);
357 self.next_field_id += 1;
358 self.field_refs.insert(field_name.clone(), obj_ref);
359 self.fields.insert(field_name, form_field);
360 self.acro_form.add_field(obj_ref);
361
362 Ok(obj_ref)
363 }
364
365 pub fn add_radio_buttons(
367 &mut self,
368 radio: RadioButton,
369 widgets: Vec<Widget>,
370 options: Option<FieldOptions>,
371 ) -> Result<ObjectReference> {
372 let mut field_dict = radio.to_dict();
373
374 if let Some(opts) = options {
376 if opts.flags.to_flags() != 0 {
377 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
378 }
379 }
380
381 let field_name = radio.name;
382 let mut form_field = FormField::new(field_dict);
383
384 for widget in widgets {
386 form_field.add_widget(widget);
387 }
388
389 let obj_ref = ObjectReference::new(self.next_field_id, 0);
391 self.next_field_id += 1;
392 self.field_refs.insert(field_name.clone(), obj_ref);
393 self.fields.insert(field_name, form_field);
394 self.acro_form.add_field(obj_ref);
395
396 Ok(obj_ref)
397 }
398
399 pub fn get_acro_form(&self) -> &AcroForm {
401 &self.acro_form
402 }
403
404 pub fn fields(&self) -> &HashMap<String, FormField> {
406 &self.fields
407 }
408
409 pub fn get_field(&self, name: &str) -> Option<&FormField> {
411 self.fields.get(name)
412 }
413
414 pub fn get_field_mut(&mut self, name: &str) -> Option<&mut FormField> {
422 self.fields.get_mut(name)
423 }
424
425 pub(crate) fn field_ref(&self, name: &str) -> Option<ObjectReference> {
440 self.field_refs.get(name).copied()
441 }
442
443 pub fn set_default_appearance(&mut self, da: impl Into<String>) {
445 self.acro_form.da = Some(da.into());
446 }
447
448 pub fn set_default_resources(&mut self, resources: Dictionary) {
450 self.acro_form.dr = Some(resources);
451 }
452}
453
454impl Default for FormManager {
455 fn default() -> Self {
456 Self::new()
457 }
458}
459
460impl FormManager {
461 pub fn field_count(&self) -> usize {
463 self.fields.len()
464 }
465
466 pub(crate) fn iter_fields_sorted(
495 &self,
496 ) -> impl Iterator<Item = (&String, &FormField, ObjectReference)> {
497 let mut keys: Vec<&String> = self.fields.keys().collect();
498 keys.sort();
499 keys.into_iter().map(move |k| {
500 let field = self
503 .fields
504 .get(k)
505 .expect("FormManager invariant: key from fields.keys() must resolve in fields");
506 let placeholder = *self.field_refs.get(k).expect(
507 "FormManager invariant: every field in `fields` must have an entry in \
508 `field_refs` — check add_*_field",
509 );
510 (k, field, placeholder)
511 })
512 }
513}
514
515#[cfg(test)]
516mod tests {
517 use super::*;
518 use crate::forms::FieldFlags;
519 use crate::geometry::{Point, Rectangle};
520
521 #[test]
522 fn test_acro_form() {
523 let mut acro_form = AcroForm::new();
524 acro_form.add_field(ObjectReference::new(1, 0));
525 acro_form.add_field(ObjectReference::new(2, 0));
526
527 let dict = acro_form.to_dict();
528 assert!(dict.get("Fields").is_some());
529 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
530 assert!(dict.get("DA").is_some());
531 }
532
533 #[test]
534 fn test_form_data() {
535 let mut form_data = FormData::new();
536 form_data.set_value("name", "John Doe");
537 form_data.set_value("email", "john@example.com");
538
539 assert_eq!(form_data.get_value("name"), Some("John Doe"));
540 assert_eq!(form_data.get_value("email"), Some("john@example.com"));
541 assert_eq!(form_data.get_value("phone"), None);
542 }
543
544 #[test]
545 fn test_form_manager_text_field() {
546 let mut manager = FormManager::new();
547
548 let field = TextField::new("username").with_default_value("guest");
549 let widget = Widget::new(Rectangle::new(
550 Point::new(100.0, 100.0),
551 Point::new(300.0, 120.0),
552 ));
553
554 let obj_ref = manager.add_text_field(field, widget, None).unwrap();
555 assert_eq!(obj_ref.number(), 1);
556 assert!(manager.get_field("username").is_some());
557 }
558
559 #[test]
560 fn test_form_manager_checkbox() {
561 let mut manager = FormManager::new();
562
563 let checkbox = CheckBox::new("agree").checked();
564 let widget = Widget::new(Rectangle::new(
565 Point::new(100.0, 100.0),
566 Point::new(115.0, 115.0),
567 ));
568
569 let obj_ref = manager.add_checkbox(checkbox, widget, None).unwrap();
570 assert_eq!(obj_ref.number(), 1);
571 assert!(manager.get_field("agree").is_some());
572 }
573
574 #[test]
584 fn iter_fields_sorted_is_non_fallible_and_ordered() {
585 let mut manager = FormManager::new();
586 let rect = Rectangle::new(Point::new(0.0, 0.0), Point::new(100.0, 20.0));
588 manager
589 .add_text_field(TextField::new("zeta"), Widget::new(rect), None)
590 .expect("add zeta");
591 manager
592 .add_text_field(TextField::new("alpha"), Widget::new(rect), None)
593 .expect("add alpha");
594 manager
595 .add_text_field(TextField::new("mu"), Widget::new(rect), None)
596 .expect("add mu");
597
598 let names: Vec<String> = manager
599 .iter_fields_sorted()
600 .map(|(name, _field, _placeholder)| name.clone())
601 .collect();
602 assert_eq!(
603 names,
604 vec!["alpha".to_string(), "mu".to_string(), "zeta".to_string()],
605 "iter_fields_sorted must yield keys in ASCII-lexicographic order"
606 );
607 }
608
609 #[test]
610 fn test_form_manager_multiple_fields() {
611 let mut manager = FormManager::new();
612
613 let text_field = TextField::new("name");
615 let text_widget = Widget::new(Rectangle::new(
616 Point::new(100.0, 200.0),
617 Point::new(300.0, 220.0),
618 ));
619 manager
620 .add_text_field(text_field, text_widget, None)
621 .unwrap();
622
623 let checkbox = CheckBox::new("subscribe");
625 let check_widget = Widget::new(Rectangle::new(
626 Point::new(100.0, 150.0),
627 Point::new(115.0, 165.0),
628 ));
629 manager.add_checkbox(checkbox, check_widget, None).unwrap();
630
631 assert_eq!(manager.fields().len(), 2);
632 assert!(manager.get_field("name").is_some());
633 assert!(manager.get_field("subscribe").is_some());
634 }
635
636 #[test]
637 fn test_acro_form_comprehensive() {
638 let mut acro_form = AcroForm::new();
639
640 assert_eq!(acro_form.fields.len(), 0);
642 assert!(acro_form.need_appearances);
643 assert!(acro_form.sig_flags.is_none());
644 assert!(acro_form.co.is_none());
645 assert!(acro_form.dr.is_none());
646 assert!(acro_form.da.is_some());
647 assert!(acro_form.q.is_none());
648
649 for i in 1..=5 {
651 acro_form.add_field(ObjectReference::new(i, 0));
652 }
653 assert_eq!(acro_form.fields.len(), 5);
654
655 acro_form.sig_flags = Some(3);
657 acro_form.co = Some(vec![ObjectReference::new(1, 0), ObjectReference::new(2, 0)]);
658 acro_form.q = Some(2); let mut dr = Dictionary::new();
661 dr.set("Font", Object::String("Helvetica".to_string()));
662 acro_form.dr = Some(dr);
663
664 let dict = acro_form.to_dict();
666
667 if let Some(Object::Array(fields)) = dict.get("Fields") {
669 assert_eq!(fields.len(), 5);
670 for (i, field) in fields.iter().enumerate() {
671 assert_eq!(
672 *field,
673 Object::Reference(ObjectReference::new((i + 1) as u32, 0))
674 );
675 }
676 } else {
677 panic!("Expected Fields array");
678 }
679
680 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
682 assert_eq!(dict.get("SigFlags"), Some(&Object::Integer(3)));
683 assert_eq!(dict.get("Q"), Some(&Object::Integer(2)));
684 assert!(dict.get("CO").is_some());
685 assert!(dict.get("DR").is_some());
686 assert!(dict.get("DA").is_some());
687 }
688
689 #[test]
690 fn test_acro_form_default() {
691 let acro_form = AcroForm::default();
692 let default_form = AcroForm::new();
693
694 assert_eq!(acro_form.fields.len(), default_form.fields.len());
695 assert_eq!(acro_form.need_appearances, default_form.need_appearances);
696 assert_eq!(acro_form.sig_flags, default_form.sig_flags);
697 assert_eq!(acro_form.da, default_form.da);
698 }
699
700 #[test]
701 fn test_acro_form_debug_clone() {
702 let mut acro_form = AcroForm::new();
703 acro_form.add_field(ObjectReference::new(1, 0));
704 acro_form.sig_flags = Some(1);
705
706 let debug_str = format!("{acro_form:?}");
707 assert!(debug_str.contains("AcroForm"));
708
709 let cloned = acro_form.clone();
710 assert_eq!(acro_form.fields, cloned.fields);
711 assert_eq!(acro_form.sig_flags, cloned.sig_flags);
712 assert_eq!(acro_form.need_appearances, cloned.need_appearances);
713 }
714
715 #[test]
716 fn test_form_data_comprehensive() {
717 let mut form_data = FormData::new();
718
719 assert_eq!(form_data.values.len(), 0);
721 assert_eq!(form_data.get_value("any"), None);
722
723 form_data.set_value("string_literal", "test");
725 form_data.set_value(String::from("string_owned"), "test2");
726 form_data.set_value("number", "42");
727 form_data.set_value("empty", "");
728 form_data.set_value("unicode", "café ñoño 你好");
729
730 assert_eq!(form_data.values.len(), 5);
731 assert_eq!(form_data.get_value("string_literal"), Some("test"));
732 assert_eq!(form_data.get_value("string_owned"), Some("test2"));
733 assert_eq!(form_data.get_value("number"), Some("42"));
734 assert_eq!(form_data.get_value("empty"), Some(""));
735 assert_eq!(form_data.get_value("unicode"), Some("café ñoño 你好"));
736
737 form_data.set_value("string_literal", "overwritten");
739 assert_eq!(form_data.get_value("string_literal"), Some("overwritten"));
740 assert_eq!(form_data.values.len(), 5); form_data.set_value("Test", "uppercase");
744 form_data.set_value("test", "lowercase");
745 assert_eq!(form_data.get_value("Test"), Some("uppercase"));
746 assert_eq!(form_data.get_value("test"), Some("lowercase"));
747 assert_eq!(form_data.values.len(), 7);
748 }
749
750 #[test]
751 fn test_form_data_edge_cases() {
752 let mut form_data = FormData::new();
753
754 form_data.set_value("", "empty_name");
756 assert_eq!(form_data.get_value(""), Some("empty_name"));
757
758 let long_name = "a".repeat(1000);
760 let long_value = "b".repeat(2000);
761 form_data.set_value(&long_name, &long_value);
762 assert_eq!(form_data.get_value(&long_name), Some(long_value.as_str()));
763
764 form_data.set_value("field/with/slashes", "value1");
766 form_data.set_value("field with spaces", "value2");
767 form_data.set_value("field.with.dots", "value3");
768 form_data.set_value("field-with-dashes", "value4");
769 form_data.set_value("field_with_underscores", "value5");
770
771 assert_eq!(form_data.get_value("field/with/slashes"), Some("value1"));
772 assert_eq!(form_data.get_value("field with spaces"), Some("value2"));
773 assert_eq!(form_data.get_value("field.with.dots"), Some("value3"));
774 assert_eq!(form_data.get_value("field-with-dashes"), Some("value4"));
775 assert_eq!(
776 form_data.get_value("field_with_underscores"),
777 Some("value5")
778 );
779 }
780
781 #[test]
782 fn test_form_data_default_debug_clone() {
783 let form_data = FormData::default();
784 assert_eq!(form_data.values.len(), 0);
785
786 let default_form = FormData::new();
787 assert_eq!(form_data.values.len(), default_form.values.len());
788
789 let debug_str = format!("{form_data:?}");
790 assert!(debug_str.contains("FormData"));
791
792 let cloned = form_data.clone();
793 assert_eq!(form_data.values.len(), cloned.values.len());
794 }
795
796 #[test]
797 fn test_form_manager_comprehensive() {
798 let mut manager = FormManager::new();
799
800 assert_eq!(manager.field_count(), 0);
802 assert_eq!(manager.fields().len(), 0);
803 assert!(manager.get_field("nonexistent").is_none());
804
805 let acroform = manager.get_acro_form();
806 assert_eq!(acroform.fields.len(), 0);
807 assert!(acroform.need_appearances);
808
809 let field1 = TextField::new("field1");
811 let widget1 = Widget::new(Rectangle::new(
812 Point::new(0.0, 0.0),
813 Point::new(100.0, 20.0),
814 ));
815 let ref1 = manager.add_text_field(field1, widget1, None).unwrap();
816 assert_eq!(ref1.number(), 1);
817
818 let field2 = TextField::new("field2");
819 let widget2 = Widget::new(Rectangle::new(
820 Point::new(0.0, 30.0),
821 Point::new(100.0, 50.0),
822 ));
823 let ref2 = manager.add_text_field(field2, widget2, None).unwrap();
824 assert_eq!(ref2.number(), 2);
825
826 let field3 = TextField::new("field3");
827 let widget3 = Widget::new(Rectangle::new(
828 Point::new(0.0, 60.0),
829 Point::new(100.0, 80.0),
830 ));
831 let ref3 = manager.add_text_field(field3, widget3, None).unwrap();
832 assert_eq!(ref3.number(), 3);
833
834 assert_eq!(manager.field_count(), 3);
835 assert_eq!(manager.get_acro_form().fields.len(), 3);
836 }
837
838 #[test]
839 fn test_form_manager_push_button() {
840 let mut manager = FormManager::new();
841
842 let button = PushButton::new("submit").with_caption("Submit");
843 let widget = Widget::new(Rectangle::new(
844 Point::new(200.0, 100.0),
845 Point::new(280.0, 130.0),
846 ));
847
848 let obj_ref = manager.add_push_button(button, widget, None).unwrap();
849 assert_eq!(obj_ref.number(), 1);
850 assert!(manager.get_field("submit").is_some());
851
852 let form_field = manager.get_field("submit").unwrap();
853 let dict = &form_field.field_dict;
854 assert_eq!(dict.get("T"), Some(&Object::String("submit".to_string())));
855 assert_eq!(dict.get("FT"), Some(&Object::Name("Btn".to_string())));
856 }
857
858 #[test]
859 fn test_form_manager_radio_buttons() {
860 let mut manager = FormManager::new();
861
862 let radio = RadioButton::new("gender")
863 .add_option("M", "Male")
864 .add_option("F", "Female")
865 .with_selected(0);
866
867 let widgets = vec![
868 Widget::new(Rectangle::new(
869 Point::new(100.0, 100.0),
870 Point::new(115.0, 115.0),
871 )),
872 Widget::new(Rectangle::new(
873 Point::new(150.0, 100.0),
874 Point::new(165.0, 115.0),
875 )),
876 ];
877
878 let obj_ref = manager.add_radio_buttons(radio, widgets, None).unwrap();
879 assert_eq!(obj_ref.number(), 1);
880 assert!(manager.get_field("gender").is_some());
881
882 let form_field = manager.get_field("gender").unwrap();
883 assert_eq!(form_field.widgets.len(), 2);
884
885 let dict = &form_field.field_dict;
886 assert_eq!(dict.get("T"), Some(&Object::String("gender".to_string())));
887 assert_eq!(dict.get("V"), Some(&Object::Name("M".to_string())));
888 }
889
890 #[test]
891 fn test_form_manager_list_box() {
892 let mut manager = FormManager::new();
893
894 let listbox = ListBox::new("languages")
895 .add_option("en", "English")
896 .add_option("es", "Spanish")
897 .add_option("fr", "French")
898 .multi_select()
899 .with_selected(vec![0, 2]);
900
901 let widget = Widget::new(Rectangle::new(
902 Point::new(100.0, 100.0),
903 Point::new(200.0, 150.0),
904 ));
905
906 let obj_ref = manager.add_list_box(listbox, widget, None).unwrap();
907 assert_eq!(obj_ref.number(), 1);
908 assert!(manager.get_field("languages").is_some());
909
910 let form_field = manager.get_field("languages").unwrap();
911 let dict = &form_field.field_dict;
912 assert_eq!(
913 dict.get("T"),
914 Some(&Object::String("languages".to_string()))
915 );
916 assert_eq!(dict.get("FT"), Some(&Object::Name("Ch".to_string())));
917 }
918
919 #[test]
920 fn test_form_manager_combo_box() {
921 let mut manager = FormManager::new();
922
923 let combo = ComboBox::new("country")
924 .add_option("US", "United States")
925 .add_option("CA", "Canada")
926 .editable()
927 .with_value("US");
928
929 let widget = Widget::new(Rectangle::new(
930 Point::new(100.0, 100.0),
931 Point::new(300.0, 120.0),
932 ));
933
934 let obj_ref = manager.add_combo_box(combo, widget, None).unwrap();
935 assert_eq!(obj_ref.number(), 1);
936 assert!(manager.get_field("country").is_some());
937
938 let form_field = manager.get_field("country").unwrap();
939 let dict = &form_field.field_dict;
940 assert_eq!(dict.get("T"), Some(&Object::String("country".to_string())));
941 assert_eq!(dict.get("V"), Some(&Object::String("US".to_string())));
942 }
943
944 #[test]
945 fn test_form_manager_with_field_options() {
946 let mut manager = FormManager::new();
947
948 let options = FieldOptions {
949 flags: FieldFlags {
950 read_only: true,
951 required: true,
952 no_export: false,
953 },
954 default_appearance: Some("/Times-Roman 12 Tf 0 g".to_string()),
955 quadding: Some(1), };
957
958 let field = TextField::new("readonly_field").with_value("Read Only");
959 let widget = Widget::new(Rectangle::new(
960 Point::new(50.0, 50.0),
961 Point::new(250.0, 70.0),
962 ));
963
964 manager
965 .add_text_field(field, widget, Some(options))
966 .unwrap();
967
968 let form_field = manager.get_field("readonly_field").unwrap();
969 let dict = &form_field.field_dict;
970
971 if let Some(Object::Integer(flags)) = dict.get("Ff") {
973 assert_ne!(*flags & (1 << 0), 0); assert_ne!(*flags & (1 << 1), 0); assert_eq!(*flags & (1 << 2), 0); } else {
977 panic!("Expected Ff field");
978 }
979
980 assert_eq!(
982 dict.get("DA"),
983 Some(&Object::String("/Times-Roman 12 Tf 0 g".to_string()))
984 );
985 assert_eq!(dict.get("Q"), Some(&Object::Integer(1)));
986 }
987
988 #[test]
989 fn test_form_manager_appearance_resources() {
990 let mut manager = FormManager::new();
991
992 manager.set_default_appearance("/Courier 10 Tf 0.5 g");
994 let acroform = manager.get_acro_form();
995 assert_eq!(acroform.da, Some("/Courier 10 Tf 0.5 g".to_string()));
996
997 let mut resources = Dictionary::new();
999 let mut font_dict = Dictionary::new();
1000 font_dict.set("F1", Object::String("Helvetica".to_string()));
1001 font_dict.set("F2", Object::String("Times-Roman".to_string()));
1002 resources.set("Font", Object::Dictionary(font_dict));
1003
1004 let mut color_dict = Dictionary::new();
1005 color_dict.set(
1006 "Red",
1007 Object::Array(vec![
1008 Object::Real(1.0),
1009 Object::Real(0.0),
1010 Object::Real(0.0),
1011 ]),
1012 );
1013 resources.set("ColorSpace", Object::Dictionary(color_dict));
1014
1015 manager.set_default_resources(resources);
1016
1017 let acroform = manager.get_acro_form();
1018 assert!(acroform.dr.is_some());
1019
1020 let dict = acroform.to_dict();
1021 assert_eq!(
1022 dict.get("DA"),
1023 Some(&Object::String("/Courier 10 Tf 0.5 g".to_string()))
1024 );
1025
1026 if let Some(Object::Dictionary(dr_dict)) = dict.get("DR") {
1027 assert!(dr_dict.get("Font").is_some());
1028 assert!(dr_dict.get("ColorSpace").is_some());
1029 } else {
1030 panic!("Expected DR dictionary");
1031 }
1032 }
1033
1034 #[test]
1035 fn test_form_manager_mixed_field_types() {
1036 let mut manager = FormManager::new();
1037
1038 let text_field = TextField::new("name").with_value("John");
1040 let text_widget = Widget::new(Rectangle::new(
1041 Point::new(10.0, 100.0),
1042 Point::new(210.0, 120.0),
1043 ));
1044 manager
1045 .add_text_field(text_field, text_widget, None)
1046 .unwrap();
1047
1048 let checkbox = CheckBox::new("agree").checked();
1049 let check_widget = Widget::new(Rectangle::new(
1050 Point::new(10.0, 80.0),
1051 Point::new(25.0, 95.0),
1052 ));
1053 manager.add_checkbox(checkbox, check_widget, None).unwrap();
1054
1055 let button = PushButton::new("submit");
1056 let button_widget = Widget::new(Rectangle::new(
1057 Point::new(10.0, 50.0),
1058 Point::new(80.0, 75.0),
1059 ));
1060 manager
1061 .add_push_button(button, button_widget, None)
1062 .unwrap();
1063
1064 let radio = RadioButton::new("choice").add_option("A", "Option A");
1065 let radio_widgets = vec![Widget::new(Rectangle::new(
1066 Point::new(10.0, 30.0),
1067 Point::new(25.0, 45.0),
1068 ))];
1069 manager
1070 .add_radio_buttons(radio, radio_widgets, None)
1071 .unwrap();
1072
1073 let listbox = ListBox::new("items").add_option("1", "Item 1");
1074 let list_widget = Widget::new(Rectangle::new(
1075 Point::new(10.0, 10.0),
1076 Point::new(110.0, 25.0),
1077 ));
1078 manager.add_list_box(listbox, list_widget, None).unwrap();
1079
1080 let combo = ComboBox::new("selection").add_option("opt", "Option");
1081 let combo_widget = Widget::new(Rectangle::new(
1082 Point::new(120.0, 10.0),
1083 Point::new(220.0, 25.0),
1084 ));
1085 manager.add_combo_box(combo, combo_widget, None).unwrap();
1086
1087 assert_eq!(manager.field_count(), 6);
1089 assert!(manager.get_field("name").is_some());
1090 assert!(manager.get_field("agree").is_some());
1091 assert!(manager.get_field("submit").is_some());
1092 assert!(manager.get_field("choice").is_some());
1093 assert!(manager.get_field("items").is_some());
1094 assert!(manager.get_field("selection").is_some());
1095
1096 let acroform = manager.get_acro_form();
1098 assert_eq!(acroform.fields.len(), 6);
1099
1100 for (i, field_ref) in acroform.fields.iter().enumerate() {
1102 assert_eq!(field_ref.number(), (i + 1) as u32);
1103 assert_eq!(field_ref.generation(), 0);
1104 }
1105 }
1106
1107 #[test]
1108 fn test_form_manager_debug_default() {
1109 let manager = FormManager::new();
1110 let debug_str = format!("{manager:?}");
1111 assert!(debug_str.contains("FormManager"));
1112
1113 let default_manager = FormManager::default();
1114 assert_eq!(manager.field_count(), default_manager.field_count());
1115 }
1116
1117 #[test]
1118 fn test_form_manager_error_scenarios() {
1119 let mut manager = FormManager::new();
1120
1121 let empty_field = TextField::new("");
1123 let widget = Widget::new(Rectangle::new(
1124 Point::new(0.0, 0.0),
1125 Point::new(100.0, 20.0),
1126 ));
1127 let result = manager.add_text_field(empty_field, widget, None);
1128 assert!(result.is_ok());
1129 assert!(manager.get_field("").is_some());
1130
1131 let field1 = TextField::new("duplicate");
1133 let widget1 = Widget::new(Rectangle::new(
1134 Point::new(0.0, 0.0),
1135 Point::new(100.0, 20.0),
1136 ));
1137 manager.add_text_field(field1, widget1, None).unwrap();
1138
1139 let field2 = TextField::new("duplicate");
1140 let widget2 = Widget::new(Rectangle::new(
1141 Point::new(0.0, 30.0),
1142 Point::new(100.0, 50.0),
1143 ));
1144 manager.add_text_field(field2, widget2, None).unwrap();
1145
1146 assert_eq!(manager.field_count(), 2); assert!(manager.get_field("duplicate").is_some());
1149 }
1150
1151 #[test]
1152 fn test_acro_form_calculation_order() {
1153 let mut acro_form = AcroForm::new();
1154
1155 let calc_order = vec![
1157 ObjectReference::new(3, 0),
1158 ObjectReference::new(1, 0),
1159 ObjectReference::new(2, 0),
1160 ];
1161 acro_form.co = Some(calc_order);
1162
1163 let dict = acro_form.to_dict();
1164
1165 if let Some(Object::Array(co_array)) = dict.get("CO") {
1166 assert_eq!(co_array.len(), 3);
1167 assert_eq!(co_array[0], Object::Reference(ObjectReference::new(3, 0)));
1168 assert_eq!(co_array[1], Object::Reference(ObjectReference::new(1, 0)));
1169 assert_eq!(co_array[2], Object::Reference(ObjectReference::new(2, 0)));
1170 } else {
1171 panic!("Expected CO array");
1172 }
1173 }
1174
1175 #[test]
1176 fn test_acro_form_without_optional_fields() {
1177 let acro_form = AcroForm::new();
1178 let dict = acro_form.to_dict();
1179
1180 assert!(dict.get("SigFlags").is_none());
1182 assert!(dict.get("CO").is_none());
1183 assert!(dict.get("DR").is_none());
1184 assert!(dict.get("Q").is_none());
1185
1186 assert!(dict.get("Fields").is_some());
1188 assert!(dict.get("NeedAppearances").is_some());
1189 assert!(dict.get("DA").is_some());
1190 }
1191}