use crate::objects::{Dictionary, Object};
#[derive(Debug, Clone, Copy)]
pub struct SubmitFormFlags {
pub include: bool,
pub html: bool,
pub coordinates: bool,
pub xml: bool,
pub include_annotations: bool,
pub pdf: bool,
pub canonical_dates: bool,
pub exclude_non_user: bool,
pub include_no_value_fields: bool,
pub export_format: bool,
}
impl Default for SubmitFormFlags {
fn default() -> Self {
Self {
include: true,
html: false,
coordinates: false,
xml: false,
include_annotations: false,
pdf: false,
canonical_dates: false,
exclude_non_user: false,
include_no_value_fields: false,
export_format: false,
}
}
}
impl SubmitFormFlags {
pub fn to_flags(&self) -> i32 {
let mut flags = 0;
if !self.include {
flags |= 1 << 0;
}
if self.html {
flags |= 1 << 2;
}
if self.coordinates {
flags |= 1 << 4;
}
if self.xml {
flags |= 1 << 5;
}
if self.include_annotations {
flags |= 1 << 7;
}
if self.pdf {
flags |= 1 << 8;
}
if self.canonical_dates {
flags |= 1 << 9;
}
if self.exclude_non_user {
flags |= 1 << 10;
}
if self.include_no_value_fields {
flags |= 1 << 11;
}
if self.export_format {
flags |= 1 << 12;
}
flags
}
}
#[derive(Debug, Clone)]
pub struct SubmitFormAction {
pub url: String,
pub fields: Vec<String>,
pub flags: SubmitFormFlags,
pub charset: Option<String>,
}
impl SubmitFormAction {
pub fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
fields: Vec::new(),
flags: SubmitFormFlags::default(),
charset: None,
}
}
pub fn as_html(mut self) -> Self {
self.flags.html = true;
self
}
pub fn as_xml(mut self) -> Self {
self.flags.xml = true;
self
}
pub fn as_pdf(mut self) -> Self {
self.flags.pdf = true;
self
}
pub fn with_fields(mut self, fields: Vec<String>) -> Self {
self.fields = fields;
self.flags.include = true;
self
}
pub fn excluding_fields(mut self, fields: Vec<String>) -> Self {
self.fields = fields;
self.flags.include = false;
self
}
pub fn with_charset(mut self, charset: impl Into<String>) -> Self {
self.charset = Some(charset.into());
self
}
pub fn with_coordinates(mut self) -> Self {
self.flags.coordinates = true;
self
}
pub fn with_annotations(mut self) -> Self {
self.flags.include_annotations = true;
self
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("SubmitForm".to_string()));
dict.set("F", Object::String(self.url.clone()));
if !self.fields.is_empty() {
let fields_array: Vec<Object> = self
.fields
.iter()
.map(|f| Object::String(f.clone()))
.collect();
dict.set("Fields", Object::Array(fields_array));
}
dict.set("Flags", Object::Integer(self.flags.to_flags() as i64));
if let Some(charset) = &self.charset {
dict.set("CharSet", Object::String(charset.clone()));
}
dict
}
}
#[derive(Debug, Clone)]
pub struct ResetFormAction {
pub fields: Vec<String>,
pub include: bool,
}
impl ResetFormAction {
pub fn new() -> Self {
Self {
fields: Vec::new(),
include: true,
}
}
pub fn with_fields(mut self, fields: Vec<String>) -> Self {
self.fields = fields;
self.include = true;
self
}
pub fn excluding_fields(mut self, fields: Vec<String>) -> Self {
self.fields = fields;
self.include = false;
self
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("ResetForm".to_string()));
if !self.fields.is_empty() {
let fields_array: Vec<Object> = self
.fields
.iter()
.map(|f| Object::String(f.clone()))
.collect();
dict.set("Fields", Object::Array(fields_array));
}
let flags = if self.include { 0 } else { 1 };
dict.set("Flags", Object::Integer(flags));
dict
}
}
impl Default for ResetFormAction {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ImportDataAction {
pub file: String,
}
impl ImportDataAction {
pub fn new(file: impl Into<String>) -> Self {
Self { file: file.into() }
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("ImportData".to_string()));
dict.set("F", Object::String(self.file.clone()));
dict
}
}
#[derive(Debug, Clone)]
pub struct HideAction {
pub targets: Vec<String>,
pub hide: bool,
}
impl HideAction {
pub fn new(targets: Vec<String>) -> Self {
Self {
targets,
hide: true,
}
}
pub fn hide(mut self) -> Self {
self.hide = true;
self
}
pub fn show(mut self) -> Self {
self.hide = false;
self
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("Hide".to_string()));
if self.targets.len() == 1 {
dict.set("T", Object::String(self.targets[0].clone()));
} else {
let targets_array: Vec<Object> = self
.targets
.iter()
.map(|t| Object::String(t.clone()))
.collect();
dict.set("T", Object::Array(targets_array));
}
dict.set("H", Object::Boolean(self.hide));
dict
}
}
#[derive(Debug, Clone)]
pub struct SetOCGStateAction {
pub state_changes: Vec<OCGStateChange>,
pub preserve_rb: bool,
}
#[derive(Debug, Clone)]
pub enum OCGStateChange {
On(Vec<String>),
Off(Vec<String>),
Toggle(Vec<String>),
}
impl SetOCGStateAction {
pub fn new() -> Self {
Self {
state_changes: Vec::new(),
preserve_rb: true,
}
}
pub fn turn_on(mut self, ocgs: Vec<String>) -> Self {
self.state_changes.push(OCGStateChange::On(ocgs));
self
}
pub fn turn_off(mut self, ocgs: Vec<String>) -> Self {
self.state_changes.push(OCGStateChange::Off(ocgs));
self
}
pub fn toggle(mut self, ocgs: Vec<String>) -> Self {
self.state_changes.push(OCGStateChange::Toggle(ocgs));
self
}
pub fn preserve_radio_buttons(mut self, preserve: bool) -> Self {
self.preserve_rb = preserve;
self
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("SetOCGState".to_string()));
let mut state_array = Vec::new();
for change in &self.state_changes {
match change {
OCGStateChange::On(ocgs) => {
state_array.push(Object::Name("ON".to_string()));
for ocg in ocgs {
state_array.push(Object::String(ocg.clone()));
}
}
OCGStateChange::Off(ocgs) => {
state_array.push(Object::Name("OFF".to_string()));
for ocg in ocgs {
state_array.push(Object::String(ocg.clone()));
}
}
OCGStateChange::Toggle(ocgs) => {
state_array.push(Object::Name("Toggle".to_string()));
for ocg in ocgs {
state_array.push(Object::String(ocg.clone()));
}
}
}
}
dict.set("State", Object::Array(state_array));
dict.set("PreserveRB", Object::Boolean(self.preserve_rb));
dict
}
}
impl Default for SetOCGStateAction {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct JavaScriptAction {
pub script: String,
}
impl JavaScriptAction {
pub fn new(script: impl Into<String>) -> Self {
Self {
script: script.into(),
}
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("JavaScript".to_string()));
dict.set("JS", Object::String(self.script.clone()));
dict
}
}
#[derive(Debug, Clone)]
pub struct SoundAction {
pub sound: String,
pub volume: f64,
pub synchronous: bool,
pub repeat: bool,
pub mix: bool,
}
impl SoundAction {
pub fn new(sound: impl Into<String>) -> Self {
Self {
sound: sound.into(),
volume: 1.0,
synchronous: false,
repeat: false,
mix: false,
}
}
pub fn with_volume(mut self, volume: f64) -> Self {
self.volume = volume.clamp(0.0, 1.0);
self
}
pub fn synchronous(mut self) -> Self {
self.synchronous = true;
self
}
pub fn repeat(mut self) -> Self {
self.repeat = true;
self
}
pub fn mix(mut self) -> Self {
self.mix = true;
self
}
pub fn to_dict(&self) -> Dictionary {
let mut dict = Dictionary::new();
dict.set("Type", Object::Name("Action".to_string()));
dict.set("S", Object::Name("Sound".to_string()));
dict.set("Sound", Object::String(self.sound.clone()));
dict.set("Volume", Object::Real(self.volume));
dict.set("Synchronous", Object::Boolean(self.synchronous));
dict.set("Repeat", Object::Boolean(self.repeat));
dict.set("Mix", Object::Boolean(self.mix));
dict
}
}