docx_reader/documents/elements/
table_of_contents.rs

1use serde::ser::{SerializeStruct, Serializer};
2use serde::Serialize;
3
4use crate::documents::*;
5
6#[derive(Debug, Clone, PartialEq)]
7pub enum TocContent {
8	Paragraph(Box<Paragraph>),
9	Table(Box<Table>),
10}
11
12impl Serialize for TocContent {
13	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14	where
15		S: Serializer,
16	{
17		match *self {
18			TocContent::Paragraph(ref p) => {
19				let mut t = serializer.serialize_struct("Paragraph", 2)?;
20				t.serialize_field("type", "paragraph")?;
21				t.serialize_field("data", p)?;
22				t.end()
23			}
24			TocContent::Table(ref c) => {
25				let mut t = serializer.serialize_struct("Table", 2)?;
26				t.serialize_field("type", "table")?;
27				t.serialize_field("data", c)?;
28				t.end()
29			}
30		}
31	}
32}
33
34#[derive(Serialize, Debug, Clone, PartialEq, Default)]
35pub struct TableOfContentsReviewData {
36	pub author: String,
37	pub date: String,
38}
39
40/// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_TOCTOC_topic_ID0ELZO1.html
41/// This struct is only used by writers
42#[derive(Serialize, Debug, Clone, PartialEq, Default)]
43pub struct TableOfContents {
44	pub instr: InstrToC,
45	pub items: Vec<TableOfContentsItem>,
46	// don't use
47	pub auto: bool,
48	pub dirty: bool,
49	/// Skip StructuredDataTag rendering
50	pub without_sdt: bool,
51	pub alias: Option<String>,
52	pub page_ref_placeholder: Option<String>,
53	// it is inserted in before toc.
54	#[serde(skip_serializing_if = "Vec::is_empty")]
55	pub before_contents: Vec<TocContent>,
56	// it is inserted in after toc.
57	#[serde(skip_serializing_if = "Vec::is_empty")]
58	pub after_contents: Vec<TocContent>,
59	#[serde(skip_serializing_if = "Option::is_none")]
60	pub delete: Option<TableOfContentsReviewData>,
61}
62
63impl TableOfContents {
64	pub fn new() -> Self {
65		Self::default()
66	}
67
68	pub fn with_instr_text(s: &str) -> Self {
69		let instr = InstrToC::with_instr_text(s);
70		Self {
71			instr,
72			..Self::default()
73		}
74	}
75
76	pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self {
77		self.instr = self.instr.heading_styles_range(start, end);
78		self
79	}
80
81	pub fn add_style_with_level(mut self, s: StyleWithLevel) -> Self {
82		self.instr = self.instr.add_style_with_level(s);
83		self
84	}
85
86	pub fn hyperlink(mut self) -> Self {
87		self.instr = self.instr.hyperlink();
88		self
89	}
90
91	pub fn alias(mut self, a: impl Into<String>) -> Self {
92		self.alias = Some(a.into());
93		self
94	}
95
96	pub fn delete(mut self, author: impl Into<String>, date: impl Into<String>) -> Self {
97		self.delete = Some(TableOfContentsReviewData {
98			author: author.into(),
99			date: date.into(),
100		});
101		self
102	}
103
104	// pub fn tc_field_level_range(mut self, start: usize, end: usize) -> Self {
105	//     self.instr = self.instr.tc_field_level_range(start, end);
106	//     self
107	// }
108
109	pub fn add_item(mut self, t: TableOfContentsItem) -> Self {
110		self.items.push(t);
111		self
112	}
113
114	pub fn auto(mut self) -> Self {
115		self.auto = true;
116		self
117	}
118
119	pub fn dirty(mut self) -> Self {
120		self.dirty = true;
121		self
122	}
123
124	pub fn add_before_paragraph(mut self, p: Paragraph) -> Self {
125		self.before_contents
126			.push(TocContent::Paragraph(Box::new(p)));
127		self
128	}
129
130	pub fn add_after_paragraph(mut self, p: Paragraph) -> Self {
131		self.after_contents.push(TocContent::Paragraph(Box::new(p)));
132		self
133	}
134
135	pub fn add_before_table(mut self, t: Table) -> Self {
136		self.before_contents.push(TocContent::Table(Box::new(t)));
137		self
138	}
139
140	pub fn add_after_table(mut self, t: Table) -> Self {
141		self.after_contents.push(TocContent::Table(Box::new(t)));
142		self
143	}
144
145	pub fn without_sdt(mut self) -> Self {
146		self.without_sdt = true;
147		self
148	}
149}