| 1 | //! Conflict pages and page versions as OneNote shows them. |
| 2 | |
| 3 | use crate::document::descendants; |
| 4 | use onestore::{ |
| 5 | ExGuid, |
| 6 | page::{Page, PageObject, PageParagraph, ParagraphContent}, |
| 7 | }; |
| 8 | |
| 9 | /// OneNote's highlight for conflicting changes on a conflict page, COLORREF. |
| 10 | pub const CONFLICTING: u32 = 0xd6d6ff; |
| 11 | |
| 12 | /// OneNote's highlight for what a page version changed since the version before it, COLORREF. |
| 13 | pub const CHANGED: u32 = 0xd6ffd6; |
| 14 | |
| 15 | /// `page` with its conflict `objects` marked as OneNote shows a conflict page's: a band |
| 16 | /// across each conflicting paragraph. |
| 17 | pub fn highlighted(page: Page, objects: &[ExGuid]) -> Page { |
| 18 | banded(page, objects, CONFLICTING) |
| 19 | } |
| 20 | |
| 21 | /// `version`, a page version, with the text it changed since `older`, the version before it, |
| 22 | /// banded as OneNote shows it; all of it without one. |
| 23 | pub fn changes(version: Page, older: Option<&Page>) -> Page { |
| 24 | let texts = |page: &Page| { |
| 25 | page.objects |
| 26 | .iter() |
| 27 | .flat_map(|object| match object { |
| 28 | PageObject::Outline(outline) => std::slice::from_ref(outline), |
| 29 | PageObject::Title(title) => title.outlines.as_slice(), |
| 30 | _ => &[], |
| 31 | }) |
| 32 | .flat_map(|outline| descendants(&outline.paragraphs, None)) |
| 33 | .filter_map(|(_, _, node)| match &node.content { |
| 34 | ParagraphContent::Text(text) => Some((text.id, text.text.text().to_owned())), |
| 35 | _ => None, |
| 36 | }) |
| 37 | .collect::<Vec<_>>() |
| 38 | }; |
| 39 | let before = older.map(texts).unwrap_or_default(); |
| 40 | let changed: Vec<ExGuid> = texts(&version) |
| 41 | .into_iter() |
| 42 | .filter(|text| !before.contains(text)) |
| 43 | .map(|(id, _)| id) |
| 44 | .collect(); |
| 45 | banded(version, &changed, CHANGED) |
| 46 | } |
| 47 | |
| 48 | fn banded(mut page: Page, objects: &[ExGuid], color: u32) -> Page { |
| 49 | fn mark(paragraphs: &mut [PageParagraph], objects: &[ExGuid], color: u32) { |
| 50 | for paragraph in paragraphs { |
| 51 | match &mut paragraph.content { |
| 52 | ParagraphContent::Table(table) => { |
| 53 | for cell in table.rows.iter_mut().flat_map(|row| &mut row.cells) { |
| 54 | mark(&mut cell.paragraphs, objects, color); |
| 55 | } |
| 56 | } |
| 57 | ParagraphContent::Text(text) |
| 58 | if objects.contains(&paragraph.id) || objects.contains(&text.id) => |
| 59 | { |
| 60 | paragraph.format.highlight = Some(color); |
| 61 | } |
| 62 | _ => {} |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | for object in &mut page.objects { |
| 67 | match object { |
| 68 | PageObject::Outline(outline) => mark(&mut outline.paragraphs, objects, color), |
| 69 | PageObject::Title(title) => { |
| 70 | for outline in &mut title.outlines { |
| 71 | mark(&mut outline.paragraphs, objects, color); |
| 72 | } |
| 73 | } |
| 74 | _ => {} |
| 75 | } |
| 76 | } |
| 77 | page |
| 78 | } |