onenote_parser/onenote/
outline.rs1use crate::errors::{ErrorKind, Result};
2use crate::fsshttpb::data::exguid::ExGuid;
3use crate::one::property::layout_alignment::LayoutAlignment;
4use crate::one::property_set::{outline_element_node, outline_group, outline_node, PropertySetId};
5use crate::onenote::content::{parse_content, Content};
6use crate::onenote::list::{parse_list, List};
7use crate::onestore::object_space::ObjectSpace;
8
9#[derive(Clone, Debug)]
16pub struct Outline {
17 pub(crate) child_level: u8,
18 pub(crate) list_spacing: Option<f32>,
19 pub(crate) indents: Vec<f32>,
20
21 pub(crate) alignment_in_parent: Option<LayoutAlignment>,
22 pub(crate) alignment_self: Option<LayoutAlignment>,
23
24 pub(crate) layout_max_height: Option<f32>,
25 pub(crate) layout_max_width: Option<f32>,
26 pub(crate) layout_reserved_width: Option<f32>,
27 pub(crate) layout_minimum_outline_width: Option<f32>,
28 pub(crate) is_layout_size_set_by_user: bool,
29 pub(crate) offset_horizontal: Option<f32>,
30 pub(crate) offset_vertical: Option<f32>,
31
32 pub(crate) items: Vec<OutlineItem>,
33}
34
35impl Outline {
36 pub fn items(&self) -> &[OutlineItem] {
38 &self.items
39 }
40
41 pub fn child_level(&self) -> u8 {
47 self.child_level
48 }
49
50 pub fn list_spacing(&self) -> Option<f32> {
56 self.list_spacing
57 }
58
59 pub fn indents(&self) -> &[f32] {
66 &self.indents
67 }
68
69 pub fn alignment_in_parent(&self) -> Option<LayoutAlignment> {
75 self.alignment_in_parent
76 }
77
78 pub fn alignment_self(&self) -> Option<LayoutAlignment> {
84 self.alignment_self
85 }
86
87 pub fn layout_max_height(&self) -> Option<f32> {
93 self.layout_max_height
94 }
95
96 pub fn layout_max_width(&self) -> Option<f32> {
102 self.layout_max_width
103 }
104
105 pub fn layout_reserved_width(&self) -> Option<f32> {
111 self.layout_reserved_width
112 }
113
114 pub fn layout_minimum_outline_width(&self) -> Option<f32> {
120 self.layout_minimum_outline_width
121 }
122
123 pub fn is_layout_size_set_by_user(&self) -> bool {
129 self.is_layout_size_set_by_user
130 }
131
132 pub fn offset_horizontal(&self) -> Option<f32> {
138 self.offset_horizontal
139 }
140
141 pub fn offset_vertical(&self) -> Option<f32> {
147 self.offset_vertical
148 }
149}
150
151#[allow(missing_docs)]
153#[derive(Clone, Debug)]
154pub enum OutlineItem {
155 Group(OutlineGroup),
156 Element(OutlineElement),
157}
158
159impl OutlineItem {
160 pub fn element(&self) -> Option<&OutlineElement> {
162 if let OutlineItem::Element(element) = self {
163 Some(element)
164 } else {
165 None
166 }
167 }
168}
169
170#[derive(Clone, Debug)]
179pub struct OutlineGroup {
180 pub(crate) child_level: u8,
181 pub(crate) outlines: Vec<OutlineItem>,
182}
183
184impl OutlineGroup {
185 pub fn child_level(&self) -> u8 {
191 self.child_level
192 }
193
194 pub fn outlines(&self) -> &[OutlineItem] {
196 &self.outlines
197 }
198}
199
200#[derive(Clone, Debug)]
207pub struct OutlineElement {
208 pub(crate) contents: Vec<Content>,
209
210 pub(crate) list_contents: Vec<List>,
211 pub(crate) list_spacing: Option<f32>,
212
213 pub(crate) child_level: u8,
214 pub(crate) children: Vec<OutlineItem>,
215}
216
217impl OutlineElement {
218 pub fn contents(&self) -> &[Content] {
220 &self.contents
221 }
222
223 pub fn list_contents(&self) -> &[List] {
232 &self.list_contents
233 }
234
235 pub fn list_spacing(&self) -> Option<f32> {
241 self.list_spacing
242 }
243
244 pub fn child_level(&self) -> u8 {
250 self.child_level
251 }
252
253 pub fn children(&self) -> &[OutlineItem] {
255 &self.children
256 }
257}
258
259pub(crate) fn parse_outline(outline_id: ExGuid, space: &ObjectSpace) -> Result<Outline> {
260 let outline_object = space
261 .get_object(outline_id)
262 .ok_or_else(|| ErrorKind::MalformedOneNoteData("outline node is missing".into()))?;
263 let data = outline_node::parse(outline_object)?;
264
265 let items = data
266 .children
267 .into_iter()
268 .map(|item_id| parse_outline_item(item_id, space))
269 .collect::<Result<_>>()?;
270
271 let outline = Outline {
272 items,
273 child_level: data.child_level,
274 list_spacing: data.list_spacing,
275 indents: data.outline_indent_distance.into_value(),
276 alignment_in_parent: data.layout_alignment_in_parent,
277 alignment_self: data.layout_alignment_self,
278 layout_max_height: data.layout_max_height,
279 layout_max_width: data.layout_max_width,
280 layout_reserved_width: data.layout_reserved_width,
281 layout_minimum_outline_width: data.layout_minimum_outline_width,
282 is_layout_size_set_by_user: data.is_layout_size_set_by_user,
283 offset_horizontal: data.offset_from_parent_horiz,
284 offset_vertical: data.offset_from_parent_vert,
285 };
286
287 Ok(outline)
288}
289
290fn parse_outline_item(item_id: ExGuid, space: &ObjectSpace) -> Result<OutlineItem> {
291 let content_type = space
292 .get_object(item_id)
293 .ok_or_else(|| ErrorKind::MalformedOneNoteData("outline item is missing".into()))?
294 .id();
295 let id = PropertySetId::from_jcid(content_type).ok_or_else(|| {
296 ErrorKind::MalformedOneNoteData(
297 format!("invalid property set id: 0x{:X}", content_type.0).into(),
298 )
299 })?;
300
301 let item = match id {
302 PropertySetId::OutlineGroup => OutlineItem::Group(parse_outline_group(item_id, space)?),
303 PropertySetId::OutlineElementNode => {
304 OutlineItem::Element(parse_outline_element(item_id, space)?)
305 }
306 _ => {
307 return Err(ErrorKind::MalformedOneNoteData(
308 format!("invalid outline item type: {:?}", id).into(),
309 )
310 .into())
311 }
312 };
313
314 Ok(item)
315}
316
317fn parse_outline_group(group_id: ExGuid, space: &ObjectSpace) -> Result<OutlineGroup> {
318 let group_object = space
319 .get_object(group_id)
320 .ok_or_else(|| ErrorKind::MalformedOneNoteData("outline group is missing".into()))?;
321 let data = outline_group::parse(group_object)?;
322
323 let outlines = data
324 .children
325 .into_iter()
326 .map(|item_id| parse_outline_item(item_id, space))
327 .collect::<Result<_>>()?;
328
329 let group = OutlineGroup {
330 child_level: data.child_level,
331 outlines,
332 };
333
334 Ok(group)
335}
336
337pub(crate) fn parse_outline_element(
338 element_id: ExGuid,
339 space: &ObjectSpace,
340) -> Result<OutlineElement> {
341 let element_object = space
342 .get_object(element_id)
343 .ok_or_else(|| ErrorKind::MalformedOneNoteData("outline element is missing".into()))?;
344 let data = outline_element_node::parse(element_object)?;
345
346 let children = data
347 .children
348 .into_iter()
349 .map(|item_id| parse_outline_item(item_id, space))
350 .collect::<Result<_>>()?;
351
352 let contents = data
353 .contents
354 .into_iter()
355 .map(|content_id| parse_content(content_id, space))
356 .collect::<Result<_>>()?;
357
358 let list_contents = data
359 .list_contents
360 .into_iter()
361 .map(|list_id| parse_list(list_id, space))
362 .collect::<Result<_>>()?;
363
364 let element = OutlineElement {
365 child_level: data.child_level,
366 list_spacing: data.list_spacing,
367 children,
368 contents,
369 list_contents,
370 };
371
372 Ok(element)
373}