use pdfrum_common::Diagnostics;
use pdfrum_doc::form::{self, FieldValues};
use crate::Document;
pub use pdfrum_doc::form::{FieldFlags, FieldKind};
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("no form field named {name:?}")]
pub struct UnknownField {
pub name: String,
}
#[derive(Debug)]
pub struct Form<'a> {
doc: &'a Document,
inner: form::Form,
values: FieldValues,
}
impl<'a> Form<'a> {
pub(crate) fn load(doc: &'a Document) -> Option<Form<'a>> {
let mut diags = Diagnostics::default();
let inner = form::Form::load(&doc.catalog(), &doc.inner, &doc.limits, &mut diags);
doc.note(&diags);
let inner = inner?;
Some(Form {
doc,
inner,
values: FieldValues::new(),
})
}
fn view(&self, index: usize, inner: &form::Field) -> Field<'a> {
Field {
doc: self.doc,
inner: inner.clone(),
index,
values: self.values.clone(),
}
}
#[must_use]
pub fn fields(&self) -> Vec<Field<'a>> {
self.inner
.fields
.iter()
.enumerate()
.map(|(index, field)| self.view(index, field))
.collect()
}
#[must_use]
pub fn field_count(&self) -> usize {
self.inner.fields.len()
}
#[must_use]
pub fn field(&self, name: &str) -> Option<Field<'a>> {
self.inner
.fields
.iter()
.enumerate()
.find(|(_, field)| field.name == name)
.map(|(index, field)| self.view(index, field))
}
#[must_use]
pub fn need_appearances(&self) -> bool {
self.inner.need_appearances
}
pub fn set(&mut self, name: &str, value: impl Into<String>) -> Result<(), UnknownField> {
if self.field(name).is_none() {
return Err(UnknownField {
name: name.to_owned(),
});
}
self.values.set(name, value);
Ok(())
}
pub fn set_checked(&mut self, name: &str, checked: bool) -> Result<(), UnknownField> {
let Some(field) = self.field(name) else {
return Err(UnknownField {
name: name.to_owned(),
});
};
let state = if checked {
field
.states()
.into_iter()
.find(|state| state != "Off")
.unwrap_or_else(|| "Yes".to_owned())
} else {
"Off".to_owned()
};
self.values.set(name, state);
Ok(())
}
pub fn edits(&self) -> impl Iterator<Item = (&str, &str)> {
self.values.iter()
}
#[cfg(feature = "edit")]
pub(crate) fn values(&self) -> &FieldValues {
&self.values
}
#[cfg(feature = "edit")]
pub(crate) fn inner(&self) -> &form::Form {
&self.inner
}
#[cfg(feature = "edit")]
pub(crate) fn document(&self) -> &'a Document {
self.doc
}
}
#[derive(Debug, Clone)]
pub struct Field<'a> {
doc: &'a Document,
inner: pdfrum_doc::form::Field,
index: usize,
values: FieldValues,
}
impl Field<'_> {
#[must_use]
pub fn name(&self) -> &str {
&self.inner.name
}
#[must_use]
pub fn kind(&self) -> FieldKind {
self.inner.kind
}
#[must_use]
pub fn flags(&self) -> FieldFlags {
self.inner.flags
}
#[must_use]
pub fn index(&self) -> usize {
self.index
}
#[must_use]
pub fn value(&self) -> String {
self.inner.value(Some(&self.values), &self.doc.inner)
}
#[must_use]
pub fn stored_value(&self) -> String {
self.inner.stored_value(&self.doc.inner)
}
#[must_use]
pub fn default_value(&self) -> String {
self.inner.default_value(&self.doc.inner)
}
#[must_use]
pub fn is_checked(&self) -> bool {
self.inner.is_checked(Some(&self.values), &self.doc.inner)
}
#[must_use]
pub fn is_read_only(&self) -> bool {
self.inner.flags.is_read_only()
}
#[must_use]
pub fn is_required(&self) -> bool {
self.inner.flags.is_required()
}
#[must_use]
pub fn states(&self) -> Vec<String> {
self.inner.states(&self.doc.inner)
}
#[must_use]
pub fn options(&self) -> Vec<String> {
self.inner.options(&self.doc.inner)
}
#[must_use]
pub fn tooltip(&self) -> Option<String> {
self.inner.tooltip(&self.doc.inner)
}
#[must_use]
pub fn widget_count(&self) -> usize {
self.inner.widgets.len()
}
}