1use crate::objects::{Dictionary, Object};
4
5#[derive(Debug, Clone, Copy)]
7pub struct SubmitFormFlags {
8 pub include: bool,
10 pub html: bool,
12 pub coordinates: bool,
14 pub xml: bool,
16 pub include_annotations: bool,
18 pub pdf: bool,
20 pub canonical_dates: bool,
22 pub exclude_non_user: bool,
24 pub include_no_value_fields: bool,
26 pub export_format: bool,
28}
29
30impl Default for SubmitFormFlags {
31 fn default() -> Self {
32 Self {
33 include: true,
34 html: false,
35 coordinates: false,
36 xml: false,
37 include_annotations: false,
38 pdf: false,
39 canonical_dates: false,
40 exclude_non_user: false,
41 include_no_value_fields: false,
42 export_format: false,
43 }
44 }
45}
46
47impl SubmitFormFlags {
48 pub fn to_flags(&self) -> i32 {
50 let mut flags = 0;
51 if !self.include {
52 flags |= 1 << 0;
53 }
54 if self.html {
55 flags |= 1 << 2;
56 }
57 if self.coordinates {
58 flags |= 1 << 4;
59 }
60 if self.xml {
61 flags |= 1 << 5;
62 }
63 if self.include_annotations {
64 flags |= 1 << 7;
65 }
66 if self.pdf {
67 flags |= 1 << 8;
68 }
69 if self.canonical_dates {
70 flags |= 1 << 9;
71 }
72 if self.exclude_non_user {
73 flags |= 1 << 10;
74 }
75 if self.include_no_value_fields {
76 flags |= 1 << 11;
77 }
78 if self.export_format {
79 flags |= 1 << 12;
80 }
81 flags
82 }
83}
84
85#[derive(Debug, Clone)]
87pub struct SubmitFormAction {
88 pub url: String,
90 pub fields: Vec<String>,
92 pub flags: SubmitFormFlags,
94 pub charset: Option<String>,
96}
97
98impl SubmitFormAction {
99 pub fn new(url: impl Into<String>) -> Self {
101 Self {
102 url: url.into(),
103 fields: Vec::new(),
104 flags: SubmitFormFlags::default(),
105 charset: None,
106 }
107 }
108
109 pub fn as_html(mut self) -> Self {
111 self.flags.html = true;
112 self
113 }
114
115 pub fn as_xml(mut self) -> Self {
117 self.flags.xml = true;
118 self
119 }
120
121 pub fn as_pdf(mut self) -> Self {
123 self.flags.pdf = true;
124 self
125 }
126
127 pub fn with_fields(mut self, fields: Vec<String>) -> Self {
129 self.fields = fields;
130 self.flags.include = true;
131 self
132 }
133
134 pub fn excluding_fields(mut self, fields: Vec<String>) -> Self {
136 self.fields = fields;
137 self.flags.include = false;
138 self
139 }
140
141 pub fn with_charset(mut self, charset: impl Into<String>) -> Self {
143 self.charset = Some(charset.into());
144 self
145 }
146
147 pub fn with_coordinates(mut self) -> Self {
149 self.flags.coordinates = true;
150 self
151 }
152
153 pub fn with_annotations(mut self) -> Self {
155 self.flags.include_annotations = true;
156 self
157 }
158
159 pub fn to_dict(&self) -> Dictionary {
161 let mut dict = Dictionary::new();
162 dict.set("Type", Object::Name("Action".to_string()));
163 dict.set("S", Object::Name("SubmitForm".to_string()));
164 dict.set("F", Object::String(self.url.clone()));
165
166 if !self.fields.is_empty() {
168 let fields_array: Vec<Object> = self
169 .fields
170 .iter()
171 .map(|f| Object::String(f.clone()))
172 .collect();
173 dict.set("Fields", Object::Array(fields_array));
174 }
175
176 dict.set("Flags", Object::Integer(self.flags.to_flags() as i64));
178
179 if let Some(charset) = &self.charset {
181 dict.set("CharSet", Object::String(charset.clone()));
182 }
183
184 dict
185 }
186}
187
188#[derive(Debug, Clone)]
190pub struct ResetFormAction {
191 pub fields: Vec<String>,
193 pub include: bool,
195}
196
197impl ResetFormAction {
198 pub fn new() -> Self {
200 Self {
201 fields: Vec::new(),
202 include: true,
203 }
204 }
205
206 pub fn with_fields(mut self, fields: Vec<String>) -> Self {
208 self.fields = fields;
209 self.include = true;
210 self
211 }
212
213 pub fn excluding_fields(mut self, fields: Vec<String>) -> Self {
215 self.fields = fields;
216 self.include = false;
217 self
218 }
219
220 pub fn to_dict(&self) -> Dictionary {
222 let mut dict = Dictionary::new();
223 dict.set("Type", Object::Name("Action".to_string()));
224 dict.set("S", Object::Name("ResetForm".to_string()));
225
226 if !self.fields.is_empty() {
228 let fields_array: Vec<Object> = self
229 .fields
230 .iter()
231 .map(|f| Object::String(f.clone()))
232 .collect();
233 dict.set("Fields", Object::Array(fields_array));
234 }
235
236 let flags = if self.include { 0 } else { 1 };
238 dict.set("Flags", Object::Integer(flags));
239
240 dict
241 }
242}
243
244impl Default for ResetFormAction {
245 fn default() -> Self {
246 Self::new()
247 }
248}
249
250#[derive(Debug, Clone)]
252pub struct ImportDataAction {
253 pub file: String,
255}
256
257impl ImportDataAction {
258 pub fn new(file: impl Into<String>) -> Self {
260 Self { file: file.into() }
261 }
262
263 pub fn to_dict(&self) -> Dictionary {
265 let mut dict = Dictionary::new();
266 dict.set("Type", Object::Name("Action".to_string()));
267 dict.set("S", Object::Name("ImportData".to_string()));
268 dict.set("F", Object::String(self.file.clone()));
269 dict
270 }
271}
272
273#[derive(Debug, Clone)]
275pub struct HideAction {
276 pub targets: Vec<String>,
278 pub hide: bool,
280}
281
282impl HideAction {
283 pub fn new(targets: Vec<String>) -> Self {
285 Self {
286 targets,
287 hide: true,
288 }
289 }
290
291 pub fn hide(mut self) -> Self {
293 self.hide = true;
294 self
295 }
296
297 pub fn show(mut self) -> Self {
299 self.hide = false;
300 self
301 }
302
303 pub fn to_dict(&self) -> Dictionary {
305 let mut dict = Dictionary::new();
306 dict.set("Type", Object::Name("Action".to_string()));
307 dict.set("S", Object::Name("Hide".to_string()));
308
309 if self.targets.len() == 1 {
311 dict.set("T", Object::String(self.targets[0].clone()));
312 } else {
313 let targets_array: Vec<Object> = self
314 .targets
315 .iter()
316 .map(|t| Object::String(t.clone()))
317 .collect();
318 dict.set("T", Object::Array(targets_array));
319 }
320
321 dict.set("H", Object::Boolean(self.hide));
322
323 dict
324 }
325}
326
327#[derive(Debug, Clone)]
329pub struct SetOCGStateAction {
330 pub state_changes: Vec<OCGStateChange>,
332 pub preserve_rb: bool,
334}
335
336#[derive(Debug, Clone)]
338pub enum OCGStateChange {
339 On(Vec<String>),
341 Off(Vec<String>),
343 Toggle(Vec<String>),
345}
346
347impl SetOCGStateAction {
348 pub fn new() -> Self {
350 Self {
351 state_changes: Vec::new(),
352 preserve_rb: true,
353 }
354 }
355
356 pub fn turn_on(mut self, ocgs: Vec<String>) -> Self {
358 self.state_changes.push(OCGStateChange::On(ocgs));
359 self
360 }
361
362 pub fn turn_off(mut self, ocgs: Vec<String>) -> Self {
364 self.state_changes.push(OCGStateChange::Off(ocgs));
365 self
366 }
367
368 pub fn toggle(mut self, ocgs: Vec<String>) -> Self {
370 self.state_changes.push(OCGStateChange::Toggle(ocgs));
371 self
372 }
373
374 pub fn preserve_radio_buttons(mut self, preserve: bool) -> Self {
376 self.preserve_rb = preserve;
377 self
378 }
379
380 pub fn to_dict(&self) -> Dictionary {
382 let mut dict = Dictionary::new();
383 dict.set("Type", Object::Name("Action".to_string()));
384 dict.set("S", Object::Name("SetOCGState".to_string()));
385
386 let mut state_array = Vec::new();
388 for change in &self.state_changes {
389 match change {
390 OCGStateChange::On(ocgs) => {
391 state_array.push(Object::Name("ON".to_string()));
392 for ocg in ocgs {
393 state_array.push(Object::String(ocg.clone()));
394 }
395 }
396 OCGStateChange::Off(ocgs) => {
397 state_array.push(Object::Name("OFF".to_string()));
398 for ocg in ocgs {
399 state_array.push(Object::String(ocg.clone()));
400 }
401 }
402 OCGStateChange::Toggle(ocgs) => {
403 state_array.push(Object::Name("Toggle".to_string()));
404 for ocg in ocgs {
405 state_array.push(Object::String(ocg.clone()));
406 }
407 }
408 }
409 }
410
411 dict.set("State", Object::Array(state_array));
412 dict.set("PreserveRB", Object::Boolean(self.preserve_rb));
413
414 dict
415 }
416}
417
418impl Default for SetOCGStateAction {
419 fn default() -> Self {
420 Self::new()
421 }
422}
423
424#[derive(Debug, Clone)]
426pub struct JavaScriptAction {
427 pub script: String,
429}
430
431impl JavaScriptAction {
432 pub fn new(script: impl Into<String>) -> Self {
434 Self {
435 script: script.into(),
436 }
437 }
438
439 pub fn to_dict(&self) -> Dictionary {
441 let mut dict = Dictionary::new();
442 dict.set("Type", Object::Name("Action".to_string()));
443 dict.set("S", Object::Name("JavaScript".to_string()));
444 dict.set("JS", Object::String(self.script.clone()));
445 dict
446 }
447}
448
449#[derive(Debug, Clone)]
451pub struct SoundAction {
452 pub sound: String,
454 pub volume: f64,
456 pub synchronous: bool,
458 pub repeat: bool,
460 pub mix: bool,
462}
463
464impl SoundAction {
465 pub fn new(sound: impl Into<String>) -> Self {
467 Self {
468 sound: sound.into(),
469 volume: 1.0,
470 synchronous: false,
471 repeat: false,
472 mix: false,
473 }
474 }
475
476 pub fn with_volume(mut self, volume: f64) -> Self {
478 self.volume = volume.clamp(0.0, 1.0);
479 self
480 }
481
482 pub fn synchronous(mut self) -> Self {
484 self.synchronous = true;
485 self
486 }
487
488 pub fn repeat(mut self) -> Self {
490 self.repeat = true;
491 self
492 }
493
494 pub fn mix(mut self) -> Self {
496 self.mix = true;
497 self
498 }
499
500 pub fn to_dict(&self) -> Dictionary {
502 let mut dict = Dictionary::new();
503 dict.set("Type", Object::Name("Action".to_string()));
504 dict.set("S", Object::Name("Sound".to_string()));
505 dict.set("Sound", Object::String(self.sound.clone()));
506 dict.set("Volume", Object::Real(self.volume));
507 dict.set("Synchronous", Object::Boolean(self.synchronous));
508 dict.set("Repeat", Object::Boolean(self.repeat));
509 dict.set("Mix", Object::Boolean(self.mix));
510 dict
511 }
512}