1use crate::flags::FieldFlags;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub struct FieldId(pub(crate) usize);
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum FieldType {
18 Text,
20 Button,
22 Choice,
24 Signature,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
30pub enum Quadding {
31 #[default]
33 Left,
34 Center,
36 Right,
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub enum FieldValue {
43 Text(String),
45 StringArray(Vec<String>),
47}
48
49#[derive(Debug, Clone, PartialEq)]
51pub struct ChoiceOption {
52 pub export: String,
54 pub display: String,
56}
57
58#[derive(Debug, Clone, Default)]
60pub struct MkDict {
61 pub border_color: Option<Vec<f32>>,
63 pub background_color: Option<Vec<f32>>,
65 pub caption: Option<String>,
67 pub rollover_caption: Option<String>,
69 pub alternate_caption: Option<String>,
71 pub text_position: Option<u32>,
73 pub rotation: Option<u32>,
75}
76
77#[derive(Debug, Clone)]
79pub struct BorderStyle {
80 pub width: f32,
82 pub style: u8,
84}
85
86impl Default for BorderStyle {
87 fn default() -> Self {
88 Self {
89 width: 1.0,
90 style: b'S',
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct FieldNode {
98 pub partial_name: String,
100 pub alternate_name: Option<String>,
102 pub mapping_name: Option<String>,
104 pub field_type: Option<FieldType>,
106 pub flags: FieldFlags,
108 pub value: Option<FieldValue>,
110 pub default_value: Option<FieldValue>,
112 pub default_appearance: Option<String>,
114 pub quadding: Option<Quadding>,
116 pub max_len: Option<u32>,
118 pub options: Vec<ChoiceOption>,
120 pub top_index: Option<u32>,
122 pub rect: Option<[f32; 4]>,
124 pub appearance_state: Option<String>,
126 pub on_state: Option<String>,
130 pub page_index: Option<usize>,
132 pub parent: Option<FieldId>,
134 pub children: Vec<FieldId>,
136 pub object_id: Option<(i32, i32)>,
138 pub has_actions: bool,
140 pub mk: Option<MkDict>,
142 pub border_style: Option<BorderStyle>,
144}
145
146#[derive(Debug)]
148pub struct FieldTree {
149 nodes: Vec<FieldNode>,
150 pub calculation_order: Vec<FieldId>,
152 pub calculate_scripts: std::collections::HashMap<FieldId, String>,
154 pub document_da: Option<String>,
156 pub document_quadding: Option<Quadding>,
158 pub need_appearances: bool,
160 pub sig_flags: u32,
162}
163
164impl FieldTree {
165 pub fn new() -> Self {
167 Self {
168 nodes: Vec::new(),
169 calculation_order: Vec::new(),
170 calculate_scripts: std::collections::HashMap::new(),
171 document_da: None,
172 document_quadding: None,
173 need_appearances: false,
174 sig_flags: 0,
175 }
176 }
177
178 pub fn alloc(&mut self, node: FieldNode) -> FieldId {
180 let id = FieldId(self.nodes.len());
181 self.nodes.push(node);
182 id
183 }
184
185 pub fn get(&self, id: FieldId) -> &FieldNode {
187 &self.nodes[id.0]
188 }
189
190 pub fn get_mut(&mut self, id: FieldId) -> &mut FieldNode {
192 &mut self.nodes[id.0]
193 }
194
195 pub fn len(&self) -> usize {
197 self.nodes.len()
198 }
199
200 pub fn is_empty(&self) -> bool {
202 self.nodes.is_empty()
203 }
204
205 pub fn roots(&self) -> Vec<FieldId> {
207 self.nodes
208 .iter()
209 .enumerate()
210 .filter(|(_, n)| n.parent.is_none())
211 .map(|(i, _)| FieldId(i))
212 .collect()
213 }
214
215 pub fn terminal_fields(&self) -> Vec<FieldId> {
217 self.nodes
218 .iter()
219 .enumerate()
220 .filter(|(_, n)| n.children.is_empty())
221 .map(|(i, _)| FieldId(i))
222 .collect()
223 }
224
225 pub fn fully_qualified_name(&self, id: FieldId) -> String {
227 let mut parts = Vec::new();
228 let mut cur = Some(id);
229 while let Some(cid) = cur {
230 let node = self.get(cid);
231 if !node.partial_name.is_empty() {
232 parts.push(node.partial_name.as_str());
233 }
234 cur = node.parent;
235 }
236 parts.reverse();
237 parts.join(".")
238 }
239
240 pub fn effective_field_type(&self, id: FieldId) -> Option<FieldType> {
242 let mut cur = Some(id);
243 while let Some(cid) = cur {
244 if let Some(ft) = self.get(cid).field_type {
245 return Some(ft);
246 }
247 cur = self.get(cid).parent;
248 }
249 None
250 }
251
252 pub fn effective_value(&self, id: FieldId) -> Option<&FieldValue> {
254 let mut cur = Some(id);
255 while let Some(cid) = cur {
256 let node = self.get(cid);
257 if node.value.is_some() {
258 return node.value.as_ref();
259 }
260 cur = node.parent;
261 }
262 None
263 }
264
265 pub fn effective_da(&self, id: FieldId) -> Option<&str> {
267 let mut cur = Some(id);
268 while let Some(cid) = cur {
269 if let Some(ref da) = self.get(cid).default_appearance {
270 return Some(da.as_str());
271 }
272 cur = self.get(cid).parent;
273 }
274 self.document_da.as_deref()
275 }
276
277 pub fn effective_quadding(&self, id: FieldId) -> Quadding {
279 let mut cur = Some(id);
280 while let Some(cid) = cur {
281 if let Some(q) = self.get(cid).quadding {
282 return q;
283 }
284 cur = self.get(cid).parent;
285 }
286 self.document_quadding.unwrap_or_default()
287 }
288
289 pub fn effective_flags(&self, id: FieldId) -> FieldFlags {
291 self.get(id).flags
292 }
293
294 pub fn effective_max_len(&self, id: FieldId) -> Option<u32> {
300 let mut cur = Some(id);
301 while let Some(cid) = cur {
302 if let Some(ml) = self.get(cid).max_len {
303 return Some(ml);
304 }
305 cur = self.get(cid).parent;
306 }
307 None
308 }
309
310 pub fn find_by_name(&self, name: &str) -> Option<FieldId> {
312 self.terminal_fields()
313 .into_iter()
314 .find(|&id| self.fully_qualified_name(id) == name)
315 }
316
317 pub fn all_ids(&self) -> impl Iterator<Item = FieldId> {
319 (0..self.nodes.len()).map(FieldId)
320 }
321}
322
323impl Default for FieldTree {
324 fn default() -> Self {
325 Self::new()
326 }
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332
333 fn make_node(name: &str) -> FieldNode {
334 FieldNode {
335 partial_name: name.into(),
336 alternate_name: None,
337 mapping_name: None,
338 field_type: None,
339 flags: FieldFlags::empty(),
340 value: None,
341 default_value: None,
342 default_appearance: None,
343 quadding: None,
344 max_len: None,
345 options: vec![],
346 top_index: None,
347 rect: None,
348 appearance_state: None,
349 on_state: None,
350 page_index: None,
351 parent: None,
352 children: vec![],
353 object_id: None,
354 has_actions: false,
355 mk: None,
356 border_style: None,
357 }
358 }
359
360 #[test]
361 fn fqn_simple() {
362 let mut tree = FieldTree::new();
363 let root = tree.alloc(make_node("form"));
364 let mut child = make_node("name");
365 child.parent = Some(root);
366 child.field_type = Some(FieldType::Text);
367 let child_id = tree.alloc(child);
368 tree.get_mut(root).children.push(child_id);
369 assert_eq!(tree.fully_qualified_name(child_id), "form.name");
370 }
371
372 #[test]
373 fn inherited_field_type() {
374 let mut tree = FieldTree::new();
375 let mut parent = make_node("group");
376 parent.field_type = Some(FieldType::Button);
377 let parent_id = tree.alloc(parent);
378 let mut child = make_node("opt1");
379 child.parent = Some(parent_id);
380 let child_id = tree.alloc(child);
381 tree.get_mut(parent_id).children.push(child_id);
382 assert_eq!(tree.effective_field_type(child_id), Some(FieldType::Button));
383 }
384
385 #[test]
386 fn inherited_da() {
387 let mut tree = FieldTree::new();
388 tree.document_da = Some("0 g /Helv 12 Tf".into());
389 let id = tree.alloc(make_node("field"));
390 assert_eq!(tree.effective_da(id), Some("0 g /Helv 12 Tf"));
391 }
392
393 #[test]
394 fn inherited_max_len() {
395 let mut tree = FieldTree::new();
396 let mut parent = make_node("group");
398 parent.max_len = Some(10);
399 let parent_id = tree.alloc(parent);
400
401 let mut child = make_node("field");
402 child.parent = Some(parent_id);
403 let child_id = tree.alloc(child);
404 tree.get_mut(parent_id).children.push(child_id);
405
406 assert_eq!(tree.effective_max_len(child_id), Some(10));
407 }
408
409 #[test]
410 fn own_max_len_overrides_parent() {
411 let mut tree = FieldTree::new();
412 let mut parent = make_node("group");
413 parent.max_len = Some(10);
414 let parent_id = tree.alloc(parent);
415
416 let mut child = make_node("field");
417 child.parent = Some(parent_id);
418 child.max_len = Some(5);
419 let child_id = tree.alloc(child);
420 tree.get_mut(parent_id).children.push(child_id);
421
422 assert_eq!(tree.effective_max_len(child_id), Some(5));
423 }
424}