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 acro_form: AcroForm,
135 next_field_id: u32,
137}
138
139impl FormManager {
140 pub fn new() -> Self {
142 Self {
143 fields: HashMap::new(),
144 acro_form: AcroForm::new(),
145 next_field_id: 1,
146 }
147 }
148
149 pub fn add_text_field(
151 &mut self,
152 field: TextField,
153 widget: Widget,
154 options: Option<FieldOptions>,
155 ) -> Result<ObjectReference> {
156 let mut field_dict = field.to_dict();
157
158 if let Some(opts) = options {
160 if opts.flags.to_flags() != 0 {
161 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
162 }
163 if let Some(da) = opts.default_appearance {
164 field_dict.set("DA", Object::String(da));
165 }
166 if let Some(q) = opts.quadding {
167 field_dict.set("Q", Object::Integer(q as i64));
168 }
169 }
170
171 let field_name = field.name.clone();
172 let mut form_field = FormField::new(field_dict);
173 form_field.add_widget(widget);
174
175 self.fields.insert(field_name, form_field);
176
177 let obj_ref = ObjectReference::new(self.next_field_id, 0);
179 self.next_field_id += 1;
180 self.acro_form.add_field(obj_ref);
181
182 Ok(obj_ref)
183 }
184
185 pub fn add_combo_box(
187 &mut self,
188 combo: ComboBox,
189 widget: Widget,
190 options: Option<FieldOptions>,
191 ) -> Result<ObjectReference> {
192 let mut field_dict = combo.to_dict();
193
194 if let Some(opts) = options {
196 if opts.flags.to_flags() != 0 {
197 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
198 }
199 if let Some(da) = opts.default_appearance {
200 field_dict.set("DA", Object::String(da));
201 }
202 }
203
204 let field_name = combo.name.clone();
205 let mut form_field = FormField::new(field_dict);
206 form_field.add_widget(widget);
207
208 self.fields.insert(field_name, form_field);
209
210 let obj_ref = ObjectReference::new(self.next_field_id, 0);
212 self.next_field_id += 1;
213 self.acro_form.add_field(obj_ref);
214
215 Ok(obj_ref)
216 }
217
218 pub fn add_list_box(
220 &mut self,
221 listbox: ListBox,
222 widget: Widget,
223 options: Option<FieldOptions>,
224 ) -> Result<ObjectReference> {
225 let mut field_dict = listbox.to_dict();
226
227 if let Some(opts) = options {
229 if opts.flags.to_flags() != 0 {
230 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
231 }
232 if let Some(da) = opts.default_appearance {
233 field_dict.set("DA", Object::String(da));
234 }
235 }
236
237 let field_name = listbox.name.clone();
238 let mut form_field = FormField::new(field_dict);
239 form_field.add_widget(widget);
240
241 self.fields.insert(field_name, form_field);
242
243 let obj_ref = ObjectReference::new(self.next_field_id, 0);
245 self.next_field_id += 1;
246 self.acro_form.add_field(obj_ref);
247
248 Ok(obj_ref)
249 }
250
251 pub fn add_radio_button(
253 &mut self,
254 radio: RadioButton,
255 widgets: Option<Vec<Widget>>,
256 options: Option<FieldOptions>,
257 ) -> Result<ObjectReference> {
258 let mut field_dict = radio.to_dict();
259
260 if let Some(opts) = options {
262 if opts.flags.to_flags() != 0 {
263 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
264 }
265 if let Some(da) = opts.default_appearance {
266 field_dict.set("DA", Object::String(da));
267 }
268 }
269
270 let field_name = radio.name.clone();
271 let mut form_field = FormField::new(field_dict);
272
273 if let Some(widgets) = widgets {
275 for widget in widgets {
276 form_field.add_widget(widget);
277 }
278 }
279
280 self.fields.insert(field_name, form_field);
281
282 let obj_ref = ObjectReference::new(self.next_field_id, 0);
284 self.next_field_id += 1;
285 self.acro_form.add_field(obj_ref);
286
287 Ok(obj_ref)
288 }
289
290 pub fn add_checkbox(
292 &mut self,
293 checkbox: CheckBox,
294 widget: Widget,
295 options: Option<FieldOptions>,
296 ) -> Result<ObjectReference> {
297 let mut field_dict = checkbox.to_dict();
298
299 if let Some(opts) = options {
301 if opts.flags.to_flags() != 0 {
302 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
303 }
304 }
305
306 let field_name = checkbox.name.clone();
307 let mut form_field = FormField::new(field_dict);
308 form_field.add_widget(widget);
309
310 self.fields.insert(field_name, form_field);
311
312 let obj_ref = ObjectReference::new(self.next_field_id, 0);
314 self.next_field_id += 1;
315 self.acro_form.add_field(obj_ref);
316
317 Ok(obj_ref)
318 }
319
320 pub fn add_push_button(
322 &mut self,
323 button: PushButton,
324 widget: Widget,
325 options: Option<FieldOptions>,
326 ) -> Result<ObjectReference> {
327 let mut field_dict = button.to_dict();
328
329 if let Some(opts) = options {
331 if opts.flags.to_flags() != 0 {
332 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
333 }
334 }
335
336 let field_name = button.name.clone();
337 let mut form_field = FormField::new(field_dict);
338 form_field.add_widget(widget);
339
340 self.fields.insert(field_name, form_field);
341
342 let obj_ref = ObjectReference::new(self.next_field_id, 0);
344 self.next_field_id += 1;
345 self.acro_form.add_field(obj_ref);
346
347 Ok(obj_ref)
348 }
349
350 pub fn add_radio_buttons(
352 &mut self,
353 radio: RadioButton,
354 widgets: Vec<Widget>,
355 options: Option<FieldOptions>,
356 ) -> Result<ObjectReference> {
357 let mut field_dict = radio.to_dict();
358
359 if let Some(opts) = options {
361 if opts.flags.to_flags() != 0 {
362 field_dict.set("Ff", Object::Integer(opts.flags.to_flags() as i64));
363 }
364 }
365
366 let field_name = radio.name.clone();
367 let mut form_field = FormField::new(field_dict);
368
369 for widget in widgets {
371 form_field.add_widget(widget);
372 }
373
374 self.fields.insert(field_name, form_field);
375
376 let obj_ref = ObjectReference::new(self.next_field_id, 0);
378 self.next_field_id += 1;
379 self.acro_form.add_field(obj_ref);
380
381 Ok(obj_ref)
382 }
383
384 pub fn get_acro_form(&self) -> &AcroForm {
386 &self.acro_form
387 }
388
389 pub fn fields(&self) -> &HashMap<String, FormField> {
391 &self.fields
392 }
393
394 pub fn get_field(&self, name: &str) -> Option<&FormField> {
396 self.fields.get(name)
397 }
398
399 pub fn set_default_appearance(&mut self, da: impl Into<String>) {
401 self.acro_form.da = Some(da.into());
402 }
403
404 pub fn set_default_resources(&mut self, resources: Dictionary) {
406 self.acro_form.dr = Some(resources);
407 }
408}
409
410impl Default for FormManager {
411 fn default() -> Self {
412 Self::new()
413 }
414}
415
416impl FormManager {
417 pub fn field_count(&self) -> usize {
419 self.fields.len()
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426 use crate::forms::FieldFlags;
427 use crate::geometry::{Point, Rectangle};
428
429 #[test]
430 fn test_acro_form() {
431 let mut acro_form = AcroForm::new();
432 acro_form.add_field(ObjectReference::new(1, 0));
433 acro_form.add_field(ObjectReference::new(2, 0));
434
435 let dict = acro_form.to_dict();
436 assert!(dict.get("Fields").is_some());
437 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
438 assert!(dict.get("DA").is_some());
439 }
440
441 #[test]
442 fn test_form_data() {
443 let mut form_data = FormData::new();
444 form_data.set_value("name", "John Doe");
445 form_data.set_value("email", "john@example.com");
446
447 assert_eq!(form_data.get_value("name"), Some("John Doe"));
448 assert_eq!(form_data.get_value("email"), Some("john@example.com"));
449 assert_eq!(form_data.get_value("phone"), None);
450 }
451
452 #[test]
453 fn test_form_manager_text_field() {
454 let mut manager = FormManager::new();
455
456 let field = TextField::new("username").with_default_value("guest");
457 let widget = Widget::new(Rectangle::new(
458 Point::new(100.0, 100.0),
459 Point::new(300.0, 120.0),
460 ));
461
462 let obj_ref = manager.add_text_field(field, widget, None).unwrap();
463 assert_eq!(obj_ref.number(), 1);
464 assert!(manager.get_field("username").is_some());
465 }
466
467 #[test]
468 fn test_form_manager_checkbox() {
469 let mut manager = FormManager::new();
470
471 let checkbox = CheckBox::new("agree").checked();
472 let widget = Widget::new(Rectangle::new(
473 Point::new(100.0, 100.0),
474 Point::new(115.0, 115.0),
475 ));
476
477 let obj_ref = manager.add_checkbox(checkbox, widget, None).unwrap();
478 assert_eq!(obj_ref.number(), 1);
479 assert!(manager.get_field("agree").is_some());
480 }
481
482 #[test]
483 fn test_form_manager_multiple_fields() {
484 let mut manager = FormManager::new();
485
486 let text_field = TextField::new("name");
488 let text_widget = Widget::new(Rectangle::new(
489 Point::new(100.0, 200.0),
490 Point::new(300.0, 220.0),
491 ));
492 manager
493 .add_text_field(text_field, text_widget, None)
494 .unwrap();
495
496 let checkbox = CheckBox::new("subscribe");
498 let check_widget = Widget::new(Rectangle::new(
499 Point::new(100.0, 150.0),
500 Point::new(115.0, 165.0),
501 ));
502 manager.add_checkbox(checkbox, check_widget, None).unwrap();
503
504 assert_eq!(manager.fields().len(), 2);
505 assert!(manager.get_field("name").is_some());
506 assert!(manager.get_field("subscribe").is_some());
507 }
508
509 #[test]
510 fn test_acro_form_comprehensive() {
511 let mut acro_form = AcroForm::new();
512
513 assert_eq!(acro_form.fields.len(), 0);
515 assert!(acro_form.need_appearances);
516 assert!(acro_form.sig_flags.is_none());
517 assert!(acro_form.co.is_none());
518 assert!(acro_form.dr.is_none());
519 assert!(acro_form.da.is_some());
520 assert!(acro_form.q.is_none());
521
522 for i in 1..=5 {
524 acro_form.add_field(ObjectReference::new(i, 0));
525 }
526 assert_eq!(acro_form.fields.len(), 5);
527
528 acro_form.sig_flags = Some(3);
530 acro_form.co = Some(vec![ObjectReference::new(1, 0), ObjectReference::new(2, 0)]);
531 acro_form.q = Some(2); let mut dr = Dictionary::new();
534 dr.set("Font", Object::String("Helvetica".to_string()));
535 acro_form.dr = Some(dr);
536
537 let dict = acro_form.to_dict();
539
540 if let Some(Object::Array(fields)) = dict.get("Fields") {
542 assert_eq!(fields.len(), 5);
543 for (i, field) in fields.iter().enumerate() {
544 assert_eq!(
545 *field,
546 Object::Reference(ObjectReference::new((i + 1) as u32, 0))
547 );
548 }
549 } else {
550 panic!("Expected Fields array");
551 }
552
553 assert_eq!(dict.get("NeedAppearances"), Some(&Object::Boolean(true)));
555 assert_eq!(dict.get("SigFlags"), Some(&Object::Integer(3)));
556 assert_eq!(dict.get("Q"), Some(&Object::Integer(2)));
557 assert!(dict.get("CO").is_some());
558 assert!(dict.get("DR").is_some());
559 assert!(dict.get("DA").is_some());
560 }
561
562 #[test]
563 fn test_acro_form_default() {
564 let acro_form = AcroForm::default();
565 let default_form = AcroForm::new();
566
567 assert_eq!(acro_form.fields.len(), default_form.fields.len());
568 assert_eq!(acro_form.need_appearances, default_form.need_appearances);
569 assert_eq!(acro_form.sig_flags, default_form.sig_flags);
570 assert_eq!(acro_form.da, default_form.da);
571 }
572
573 #[test]
574 fn test_acro_form_debug_clone() {
575 let mut acro_form = AcroForm::new();
576 acro_form.add_field(ObjectReference::new(1, 0));
577 acro_form.sig_flags = Some(1);
578
579 let debug_str = format!("{acro_form:?}");
580 assert!(debug_str.contains("AcroForm"));
581
582 let cloned = acro_form.clone();
583 assert_eq!(acro_form.fields, cloned.fields);
584 assert_eq!(acro_form.sig_flags, cloned.sig_flags);
585 assert_eq!(acro_form.need_appearances, cloned.need_appearances);
586 }
587
588 #[test]
589 fn test_form_data_comprehensive() {
590 let mut form_data = FormData::new();
591
592 assert_eq!(form_data.values.len(), 0);
594 assert_eq!(form_data.get_value("any"), None);
595
596 form_data.set_value("string_literal", "test");
598 form_data.set_value(String::from("string_owned"), "test2");
599 form_data.set_value("number", "42");
600 form_data.set_value("empty", "");
601 form_data.set_value("unicode", "café ñoño 你好");
602
603 assert_eq!(form_data.values.len(), 5);
604 assert_eq!(form_data.get_value("string_literal"), Some("test"));
605 assert_eq!(form_data.get_value("string_owned"), Some("test2"));
606 assert_eq!(form_data.get_value("number"), Some("42"));
607 assert_eq!(form_data.get_value("empty"), Some(""));
608 assert_eq!(form_data.get_value("unicode"), Some("café ñoño 你好"));
609
610 form_data.set_value("string_literal", "overwritten");
612 assert_eq!(form_data.get_value("string_literal"), Some("overwritten"));
613 assert_eq!(form_data.values.len(), 5); form_data.set_value("Test", "uppercase");
617 form_data.set_value("test", "lowercase");
618 assert_eq!(form_data.get_value("Test"), Some("uppercase"));
619 assert_eq!(form_data.get_value("test"), Some("lowercase"));
620 assert_eq!(form_data.values.len(), 7);
621 }
622
623 #[test]
624 fn test_form_data_edge_cases() {
625 let mut form_data = FormData::new();
626
627 form_data.set_value("", "empty_name");
629 assert_eq!(form_data.get_value(""), Some("empty_name"));
630
631 let long_name = "a".repeat(1000);
633 let long_value = "b".repeat(2000);
634 form_data.set_value(&long_name, &long_value);
635 assert_eq!(form_data.get_value(&long_name), Some(long_value.as_str()));
636
637 form_data.set_value("field/with/slashes", "value1");
639 form_data.set_value("field with spaces", "value2");
640 form_data.set_value("field.with.dots", "value3");
641 form_data.set_value("field-with-dashes", "value4");
642 form_data.set_value("field_with_underscores", "value5");
643
644 assert_eq!(form_data.get_value("field/with/slashes"), Some("value1"));
645 assert_eq!(form_data.get_value("field with spaces"), Some("value2"));
646 assert_eq!(form_data.get_value("field.with.dots"), Some("value3"));
647 assert_eq!(form_data.get_value("field-with-dashes"), Some("value4"));
648 assert_eq!(
649 form_data.get_value("field_with_underscores"),
650 Some("value5")
651 );
652 }
653
654 #[test]
655 fn test_form_data_default_debug_clone() {
656 let form_data = FormData::default();
657 assert_eq!(form_data.values.len(), 0);
658
659 let default_form = FormData::new();
660 assert_eq!(form_data.values.len(), default_form.values.len());
661
662 let debug_str = format!("{form_data:?}");
663 assert!(debug_str.contains("FormData"));
664
665 let cloned = form_data.clone();
666 assert_eq!(form_data.values.len(), cloned.values.len());
667 }
668
669 #[test]
670 fn test_form_manager_comprehensive() {
671 let mut manager = FormManager::new();
672
673 assert_eq!(manager.field_count(), 0);
675 assert_eq!(manager.fields().len(), 0);
676 assert!(manager.get_field("nonexistent").is_none());
677
678 let acroform = manager.get_acro_form();
679 assert_eq!(acroform.fields.len(), 0);
680 assert!(acroform.need_appearances);
681
682 let field1 = TextField::new("field1");
684 let widget1 = Widget::new(Rectangle::new(
685 Point::new(0.0, 0.0),
686 Point::new(100.0, 20.0),
687 ));
688 let ref1 = manager.add_text_field(field1, widget1, None).unwrap();
689 assert_eq!(ref1.number(), 1);
690
691 let field2 = TextField::new("field2");
692 let widget2 = Widget::new(Rectangle::new(
693 Point::new(0.0, 30.0),
694 Point::new(100.0, 50.0),
695 ));
696 let ref2 = manager.add_text_field(field2, widget2, None).unwrap();
697 assert_eq!(ref2.number(), 2);
698
699 let field3 = TextField::new("field3");
700 let widget3 = Widget::new(Rectangle::new(
701 Point::new(0.0, 60.0),
702 Point::new(100.0, 80.0),
703 ));
704 let ref3 = manager.add_text_field(field3, widget3, None).unwrap();
705 assert_eq!(ref3.number(), 3);
706
707 assert_eq!(manager.field_count(), 3);
708 assert_eq!(manager.get_acro_form().fields.len(), 3);
709 }
710
711 #[test]
712 fn test_form_manager_push_button() {
713 let mut manager = FormManager::new();
714
715 let button = PushButton::new("submit").with_caption("Submit");
716 let widget = Widget::new(Rectangle::new(
717 Point::new(200.0, 100.0),
718 Point::new(280.0, 130.0),
719 ));
720
721 let obj_ref = manager.add_push_button(button, widget, None).unwrap();
722 assert_eq!(obj_ref.number(), 1);
723 assert!(manager.get_field("submit").is_some());
724
725 let form_field = manager.get_field("submit").unwrap();
726 let dict = &form_field.field_dict;
727 assert_eq!(dict.get("T"), Some(&Object::String("submit".to_string())));
728 assert_eq!(dict.get("FT"), Some(&Object::Name("Btn".to_string())));
729 }
730
731 #[test]
732 fn test_form_manager_radio_buttons() {
733 let mut manager = FormManager::new();
734
735 let radio = RadioButton::new("gender")
736 .add_option("M", "Male")
737 .add_option("F", "Female")
738 .with_selected(0);
739
740 let widgets = vec![
741 Widget::new(Rectangle::new(
742 Point::new(100.0, 100.0),
743 Point::new(115.0, 115.0),
744 )),
745 Widget::new(Rectangle::new(
746 Point::new(150.0, 100.0),
747 Point::new(165.0, 115.0),
748 )),
749 ];
750
751 let obj_ref = manager.add_radio_buttons(radio, widgets, None).unwrap();
752 assert_eq!(obj_ref.number(), 1);
753 assert!(manager.get_field("gender").is_some());
754
755 let form_field = manager.get_field("gender").unwrap();
756 assert_eq!(form_field.widgets.len(), 2);
757
758 let dict = &form_field.field_dict;
759 assert_eq!(dict.get("T"), Some(&Object::String("gender".to_string())));
760 assert_eq!(dict.get("V"), Some(&Object::Name("M".to_string())));
761 }
762
763 #[test]
764 fn test_form_manager_list_box() {
765 let mut manager = FormManager::new();
766
767 let listbox = ListBox::new("languages")
768 .add_option("en", "English")
769 .add_option("es", "Spanish")
770 .add_option("fr", "French")
771 .multi_select()
772 .with_selected(vec![0, 2]);
773
774 let widget = Widget::new(Rectangle::new(
775 Point::new(100.0, 100.0),
776 Point::new(200.0, 150.0),
777 ));
778
779 let obj_ref = manager.add_list_box(listbox, widget, None).unwrap();
780 assert_eq!(obj_ref.number(), 1);
781 assert!(manager.get_field("languages").is_some());
782
783 let form_field = manager.get_field("languages").unwrap();
784 let dict = &form_field.field_dict;
785 assert_eq!(
786 dict.get("T"),
787 Some(&Object::String("languages".to_string()))
788 );
789 assert_eq!(dict.get("FT"), Some(&Object::Name("Ch".to_string())));
790 }
791
792 #[test]
793 fn test_form_manager_combo_box() {
794 let mut manager = FormManager::new();
795
796 let combo = ComboBox::new("country")
797 .add_option("US", "United States")
798 .add_option("CA", "Canada")
799 .editable()
800 .with_value("US");
801
802 let widget = Widget::new(Rectangle::new(
803 Point::new(100.0, 100.0),
804 Point::new(300.0, 120.0),
805 ));
806
807 let obj_ref = manager.add_combo_box(combo, widget, None).unwrap();
808 assert_eq!(obj_ref.number(), 1);
809 assert!(manager.get_field("country").is_some());
810
811 let form_field = manager.get_field("country").unwrap();
812 let dict = &form_field.field_dict;
813 assert_eq!(dict.get("T"), Some(&Object::String("country".to_string())));
814 assert_eq!(dict.get("V"), Some(&Object::String("US".to_string())));
815 }
816
817 #[test]
818 fn test_form_manager_with_field_options() {
819 let mut manager = FormManager::new();
820
821 let options = FieldOptions {
822 flags: FieldFlags {
823 read_only: true,
824 required: true,
825 no_export: false,
826 },
827 default_appearance: Some("/Times-Roman 12 Tf 0 g".to_string()),
828 quadding: Some(1), };
830
831 let field = TextField::new("readonly_field").with_value("Read Only");
832 let widget = Widget::new(Rectangle::new(
833 Point::new(50.0, 50.0),
834 Point::new(250.0, 70.0),
835 ));
836
837 manager
838 .add_text_field(field, widget, Some(options))
839 .unwrap();
840
841 let form_field = manager.get_field("readonly_field").unwrap();
842 let dict = &form_field.field_dict;
843
844 if let Some(Object::Integer(flags)) = dict.get("Ff") {
846 assert_ne!(*flags & (1 << 0), 0); assert_ne!(*flags & (1 << 1), 0); assert_eq!(*flags & (1 << 2), 0); } else {
850 panic!("Expected Ff field");
851 }
852
853 assert_eq!(
855 dict.get("DA"),
856 Some(&Object::String("/Times-Roman 12 Tf 0 g".to_string()))
857 );
858 assert_eq!(dict.get("Q"), Some(&Object::Integer(1)));
859 }
860
861 #[test]
862 fn test_form_manager_appearance_resources() {
863 let mut manager = FormManager::new();
864
865 manager.set_default_appearance("/Courier 10 Tf 0.5 g");
867 let acroform = manager.get_acro_form();
868 assert_eq!(acroform.da, Some("/Courier 10 Tf 0.5 g".to_string()));
869
870 let mut resources = Dictionary::new();
872 let mut font_dict = Dictionary::new();
873 font_dict.set("F1", Object::String("Helvetica".to_string()));
874 font_dict.set("F2", Object::String("Times-Roman".to_string()));
875 resources.set("Font", Object::Dictionary(font_dict));
876
877 let mut color_dict = Dictionary::new();
878 color_dict.set(
879 "Red",
880 Object::Array(vec![
881 Object::Real(1.0),
882 Object::Real(0.0),
883 Object::Real(0.0),
884 ]),
885 );
886 resources.set("ColorSpace", Object::Dictionary(color_dict));
887
888 manager.set_default_resources(resources);
889
890 let acroform = manager.get_acro_form();
891 assert!(acroform.dr.is_some());
892
893 let dict = acroform.to_dict();
894 assert_eq!(
895 dict.get("DA"),
896 Some(&Object::String("/Courier 10 Tf 0.5 g".to_string()))
897 );
898
899 if let Some(Object::Dictionary(dr_dict)) = dict.get("DR") {
900 assert!(dr_dict.get("Font").is_some());
901 assert!(dr_dict.get("ColorSpace").is_some());
902 } else {
903 panic!("Expected DR dictionary");
904 }
905 }
906
907 #[test]
908 fn test_form_manager_mixed_field_types() {
909 let mut manager = FormManager::new();
910
911 let text_field = TextField::new("name").with_value("John");
913 let text_widget = Widget::new(Rectangle::new(
914 Point::new(10.0, 100.0),
915 Point::new(210.0, 120.0),
916 ));
917 manager
918 .add_text_field(text_field, text_widget, None)
919 .unwrap();
920
921 let checkbox = CheckBox::new("agree").checked();
922 let check_widget = Widget::new(Rectangle::new(
923 Point::new(10.0, 80.0),
924 Point::new(25.0, 95.0),
925 ));
926 manager.add_checkbox(checkbox, check_widget, None).unwrap();
927
928 let button = PushButton::new("submit");
929 let button_widget = Widget::new(Rectangle::new(
930 Point::new(10.0, 50.0),
931 Point::new(80.0, 75.0),
932 ));
933 manager
934 .add_push_button(button, button_widget, None)
935 .unwrap();
936
937 let radio = RadioButton::new("choice").add_option("A", "Option A");
938 let radio_widgets = vec![Widget::new(Rectangle::new(
939 Point::new(10.0, 30.0),
940 Point::new(25.0, 45.0),
941 ))];
942 manager
943 .add_radio_buttons(radio, radio_widgets, None)
944 .unwrap();
945
946 let listbox = ListBox::new("items").add_option("1", "Item 1");
947 let list_widget = Widget::new(Rectangle::new(
948 Point::new(10.0, 10.0),
949 Point::new(110.0, 25.0),
950 ));
951 manager.add_list_box(listbox, list_widget, None).unwrap();
952
953 let combo = ComboBox::new("selection").add_option("opt", "Option");
954 let combo_widget = Widget::new(Rectangle::new(
955 Point::new(120.0, 10.0),
956 Point::new(220.0, 25.0),
957 ));
958 manager.add_combo_box(combo, combo_widget, None).unwrap();
959
960 assert_eq!(manager.field_count(), 6);
962 assert!(manager.get_field("name").is_some());
963 assert!(manager.get_field("agree").is_some());
964 assert!(manager.get_field("submit").is_some());
965 assert!(manager.get_field("choice").is_some());
966 assert!(manager.get_field("items").is_some());
967 assert!(manager.get_field("selection").is_some());
968
969 let acroform = manager.get_acro_form();
971 assert_eq!(acroform.fields.len(), 6);
972
973 for (i, field_ref) in acroform.fields.iter().enumerate() {
975 assert_eq!(field_ref.number(), (i + 1) as u32);
976 assert_eq!(field_ref.generation(), 0);
977 }
978 }
979
980 #[test]
981 fn test_form_manager_debug_default() {
982 let manager = FormManager::new();
983 let debug_str = format!("{manager:?}");
984 assert!(debug_str.contains("FormManager"));
985
986 let default_manager = FormManager::default();
987 assert_eq!(manager.field_count(), default_manager.field_count());
988 }
989
990 #[test]
991 fn test_form_manager_error_scenarios() {
992 let mut manager = FormManager::new();
993
994 let empty_field = TextField::new("");
996 let widget = Widget::new(Rectangle::new(
997 Point::new(0.0, 0.0),
998 Point::new(100.0, 20.0),
999 ));
1000 let result = manager.add_text_field(empty_field, widget, None);
1001 assert!(result.is_ok());
1002 assert!(manager.get_field("").is_some());
1003
1004 let field1 = TextField::new("duplicate");
1006 let widget1 = Widget::new(Rectangle::new(
1007 Point::new(0.0, 0.0),
1008 Point::new(100.0, 20.0),
1009 ));
1010 manager.add_text_field(field1, widget1, None).unwrap();
1011
1012 let field2 = TextField::new("duplicate");
1013 let widget2 = Widget::new(Rectangle::new(
1014 Point::new(0.0, 30.0),
1015 Point::new(100.0, 50.0),
1016 ));
1017 manager.add_text_field(field2, widget2, None).unwrap();
1018
1019 assert_eq!(manager.field_count(), 2); assert!(manager.get_field("duplicate").is_some());
1022 }
1023
1024 #[test]
1025 fn test_acro_form_calculation_order() {
1026 let mut acro_form = AcroForm::new();
1027
1028 let calc_order = vec![
1030 ObjectReference::new(3, 0),
1031 ObjectReference::new(1, 0),
1032 ObjectReference::new(2, 0),
1033 ];
1034 acro_form.co = Some(calc_order.clone());
1035
1036 let dict = acro_form.to_dict();
1037
1038 if let Some(Object::Array(co_array)) = dict.get("CO") {
1039 assert_eq!(co_array.len(), 3);
1040 assert_eq!(co_array[0], Object::Reference(ObjectReference::new(3, 0)));
1041 assert_eq!(co_array[1], Object::Reference(ObjectReference::new(1, 0)));
1042 assert_eq!(co_array[2], Object::Reference(ObjectReference::new(2, 0)));
1043 } else {
1044 panic!("Expected CO array");
1045 }
1046 }
1047
1048 #[test]
1049 fn test_acro_form_without_optional_fields() {
1050 let acro_form = AcroForm::new();
1051 let dict = acro_form.to_dict();
1052
1053 assert!(dict.get("SigFlags").is_none());
1055 assert!(dict.get("CO").is_none());
1056 assert!(dict.get("DR").is_none());
1057 assert!(dict.get("Q").is_none());
1058
1059 assert!(dict.get("Fields").is_some());
1061 assert!(dict.get("NeedAppearances").is_some());
1062 assert!(dict.get("DA").is_some());
1063 }
1064}