use crate::error::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum XfaFieldType {
Text,
Checkbox,
RadioGroup,
Button,
Dropdown,
Signature,
DateTime,
Numeric,
Password,
Image,
Barcode,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct XfaRect {
pub x: f64,
pub y: f64,
pub width: f64,
pub height: f64,
}
#[derive(Debug, Clone)]
pub struct XfaWidget {
pub page: usize,
pub rect: XfaRect,
pub on_value: Option<String>,
}
#[derive(Debug, Clone)]
pub struct XfaFieldOption {
pub display: String,
pub save: String,
}
#[derive(Debug, Clone)]
pub struct XfaField {
pub name: String,
pub som_path: String,
pub field_type: XfaFieldType,
pub value: String,
pub read_only: bool,
pub required: bool,
pub multiline: bool,
pub hidden: bool,
pub options: Vec<XfaFieldOption>,
pub on_value: Option<String>,
pub off_value: Option<String>,
pub page: Option<usize>,
pub rect: Option<XfaRect>,
pub widgets: Vec<XfaWidget>,
pub bound_to_data: bool,
pub bind_none: bool,
}
#[derive(Debug, Clone)]
pub struct XfaFormModel {
pub page_count: usize,
pub fields: Vec<XfaField>,
}
#[derive(Debug, Clone, Copy)]
pub enum XfaFieldValue<'a> {
Text(&'a str),
Checkbox(bool),
Radio(&'a str),
}
#[derive(Debug, Clone)]
pub struct XfaSetOutcome {
pub raw_value: String,
pub persisted_to_datasets: bool,
}
pub(crate) fn field_type_from_engine(t: pdf_engine::xfa::XfaFieldType) -> XfaFieldType {
use pdf_engine::xfa::XfaFieldType as E;
match t {
E::Text => XfaFieldType::Text,
E::Checkbox => XfaFieldType::Checkbox,
E::RadioGroup => XfaFieldType::RadioGroup,
E::Button => XfaFieldType::Button,
E::Dropdown => XfaFieldType::Dropdown,
E::Signature => XfaFieldType::Signature,
E::DateTime => XfaFieldType::DateTime,
E::Numeric => XfaFieldType::Numeric,
E::Password => XfaFieldType::Password,
E::Image => XfaFieldType::Image,
E::Barcode => XfaFieldType::Barcode,
}
}
pub(crate) fn field_from_engine(f: &pdf_engine::xfa::XfaFieldModel) -> XfaField {
let rect = |r: &pdf_engine::xfa::XfaRect| XfaRect {
x: r.x,
y: r.y,
width: r.width,
height: r.height,
};
XfaField {
name: f.name.clone(),
som_path: f.som_path.clone(),
field_type: field_type_from_engine(f.field_type),
value: f.value.clone(),
read_only: f.read_only,
required: f.required,
multiline: f.multiline,
hidden: f.hidden,
options: f
.options
.iter()
.map(|o| XfaFieldOption {
display: o.display.clone(),
save: o.save.clone(),
})
.collect(),
on_value: f.on_value.clone(),
off_value: f.off_value.clone(),
page: f.page,
rect: f.rect.as_ref().map(rect),
widgets: f
.widgets
.iter()
.map(|w| XfaWidget {
page: w.page,
rect: rect(&w.rect),
on_value: w.on_value.clone(),
})
.collect(),
bound_to_data: f.bound_to_data,
bind_none: f.bind_none,
}
}
pub(crate) fn map_xfa_err(e: pdf_engine::xfa::XfaError) -> Error {
use pdf_engine::xfa::XfaError as X;
match e {
X::PacketNotFound(_) => {
Error::Unsupported("document has no XFA form (template packet missing)".to_string())
}
X::FieldNotFound(name) => Error::Unsupported(format!("XFA field not found: {name}")),
X::FieldReadOnly(name) => Error::Unsupported(format!("XFA field is read-only: {name}")),
X::InvalidFieldValue { name, reason } => {
Error::Unsupported(format!("invalid value for XFA field {name}: {reason}"))
}
other => crate::error::internal_error(other.to_string()),
}
}