diff --git a/CMakeLists.txt b/CMakeLists.txt index 41370639..843381ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,7 +99,6 @@ set(ODR_SOURCE_FILES "src/odr/internal/cfb/cfb_util.cpp" "src/odr/internal/common/document.cpp" - "src/odr/internal/common/document_element.cpp" "src/odr/internal/common/file.cpp" "src/odr/internal/common/filesystem.cpp" "src/odr/internal/common/image_file.cpp" @@ -133,31 +132,30 @@ set(ODR_SOURCE_FILES "src/odr/internal/odf/odf_crypto.cpp" "src/odr/internal/odf/odf_document.cpp" - "src/odr/internal/odf/odf_element.cpp" + "src/odr/internal/odf/odf_element_registry.cpp" "src/odr/internal/odf/odf_file.cpp" "src/odr/internal/odf/odf_manifest.cpp" "src/odr/internal/odf/odf_meta.cpp" "src/odr/internal/odf/odf_parser.cpp" - "src/odr/internal/odf/odf_spreadsheet.cpp" "src/odr/internal/odf/odf_style.cpp" "src/odr/internal/oldms/oldms_file.cpp" - "src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp" - "src/odr/internal/ooxml/presentation/ooxml_presentation_element.cpp" - "src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp" - "src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp" - "src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element.cpp" - "src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp" - "src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_style.cpp" - "src/odr/internal/ooxml/text/ooxml_text_document.cpp" - "src/odr/internal/ooxml/text/ooxml_text_element.cpp" - "src/odr/internal/ooxml/text/ooxml_text_parser.cpp" - "src/odr/internal/ooxml/text/ooxml_text_style.cpp" - "src/odr/internal/ooxml/ooxml_crypto.cpp" - "src/odr/internal/ooxml/ooxml_file.cpp" - "src/odr/internal/ooxml/ooxml_meta.cpp" - "src/odr/internal/ooxml/ooxml_util.cpp" + #"src/odr/internal/ooxml/presentation/ooxml_presentation_document.cpp" + #"src/odr/internal/ooxml/presentation/ooxml_presentation_element.cpp" + #"src/odr/internal/ooxml/presentation/ooxml_presentation_parser.cpp" + #"src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp" + #"src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element.cpp" + #"src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp" + #"src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_style.cpp" + #"src/odr/internal/ooxml/text/ooxml_text_document.cpp" + #"src/odr/internal/ooxml/text/ooxml_text_element.cpp" + #"src/odr/internal/ooxml/text/ooxml_text_parser.cpp" + #"src/odr/internal/ooxml/text/ooxml_text_style.cpp" + #"src/odr/internal/ooxml/ooxml_crypto.cpp" + #"src/odr/internal/ooxml/ooxml_file.cpp" + #"src/odr/internal/ooxml/ooxml_meta.cpp" + #"src/odr/internal/ooxml/ooxml_util.cpp" "src/odr/internal/pdf/pdf_cmap.cpp" "src/odr/internal/pdf/pdf_cmap_parser.cpp" diff --git a/src/odr/document.cpp b/src/odr/document.cpp index ccd33bc8..23b0b98a 100644 --- a/src/odr/document.cpp +++ b/src/odr/document.cpp @@ -39,7 +39,7 @@ DocumentType Document::document_type() const noexcept { } Element Document::root_element() const { - return {m_impl.get(), m_impl->root_element()}; + return {m_impl->element_adapter(), m_impl->root_element()}; } Filesystem Document::as_filesystem() const { diff --git a/src/odr/document_element.cpp b/src/odr/document_element.cpp index c20046bf..854971dd 100644 --- a/src/odr/document_element.cpp +++ b/src/odr/document_element.cpp @@ -4,129 +4,164 @@ #include #include -#include namespace odr { Element::Element() = default; -Element::Element(const internal::abstract::Document *document, - internal::abstract::Element *element) - : m_document{document}, m_element{element} {} - -bool Element::operator==(const Element &rhs) const { - return m_element == rhs.m_element; -} - -bool Element::operator!=(const Element &rhs) const { - return m_element != rhs.m_element; -} +Element::Element(const internal::abstract::ElementAdapter *adapter, + const ExtendedElementIdentifier identifier) + : m_adapter{adapter}, m_identifier{identifier} {} Element::operator bool() const { return exists_(); } -bool Element::exists_() const { return m_element != nullptr; } +bool Element::exists_() const { + return m_adapter != nullptr && !m_identifier.is_null(); +} ElementType Element::type() const { - return exists_() ? m_element->type(m_document) : ElementType::none; + return exists_() ? m_adapter->element_type(m_identifier) : ElementType::none; } Element Element::parent() const { - return exists_() ? Element(m_document, m_element->parent(m_document)) + return exists_() ? Element(m_adapter, m_adapter->element_parent(m_identifier)) : Element(); } Element Element::first_child() const { - return exists_() ? Element(m_document, m_element->first_child(m_document)) - : Element(); + return exists_() + ? Element(m_adapter, m_adapter->element_first_child(m_identifier)) + : Element(); } Element Element::previous_sibling() const { - return exists_() - ? Element(m_document, m_element->previous_sibling(m_document)) - : Element(); + return exists_() ? Element(m_adapter, + m_adapter->element_previous_sibling(m_identifier)) + : Element(); } Element Element::next_sibling() const { - return exists_() ? Element(m_document, m_element->next_sibling(m_document)) - : Element(); + return exists_() + ? Element(m_adapter, m_adapter->element_next_sibling(m_identifier)) + : Element(); } bool Element::is_editable() const { - return exists_() ? m_element->is_editable(m_document) : false; + return exists_() ? m_adapter->element_is_editable(m_identifier) : false; } -TextRoot Element::as_text_root() const { return {m_document, m_element}; } +TextRoot Element::as_text_root() const { + return {m_adapter, m_identifier, m_adapter->text_root_adapter(m_identifier)}; +} -Slide Element::as_slide() const { return {m_document, m_element}; } +Slide Element::as_slide() const { + return {m_adapter, m_identifier, m_adapter->slide_adapter(m_identifier)}; +} -Sheet Element::as_sheet() const { return {m_document, m_element}; } +Sheet Element::as_sheet() const { + return {m_adapter, m_identifier, m_adapter->sheet_adapter(m_identifier)}; +} -Page Element::as_page() const { return {m_document, m_element}; } +Page Element::as_page() const { + return {m_adapter, m_identifier, m_adapter->page_adapter(m_identifier)}; +} -MasterPage Element::as_master_page() const { return {m_document, m_element}; } +MasterPage Element::as_master_page() const { + return {m_adapter, m_identifier, + m_adapter->master_page_adapter(m_identifier)}; +} -LineBreak Element::as_line_break() const { return {m_document, m_element}; } +LineBreak Element::as_line_break() const { + return {m_adapter, m_identifier, m_adapter->line_break_adapter(m_identifier)}; +} -Paragraph Element::as_paragraph() const { return {m_document, m_element}; } +Paragraph Element::as_paragraph() const { + return {m_adapter, m_identifier, m_adapter->paragraph_adapter(m_identifier)}; +} -Span Element::as_span() const { return {m_document, m_element}; } +Span Element::as_span() const { + return {m_adapter, m_identifier, m_adapter->span_adapter(m_identifier)}; +} -Text Element::as_text() const { return {m_document, m_element}; } +Text Element::as_text() const { + return {m_adapter, m_identifier, m_adapter->text_adapter(m_identifier)}; +} -Link Element::as_link() const { return {m_document, m_element}; } +Link Element::as_link() const { + return {m_adapter, m_identifier, m_adapter->link_adapter(m_identifier)}; +} -Bookmark Element::as_bookmark() const { return {m_document, m_element}; } +Bookmark Element::as_bookmark() const { + return {m_adapter, m_identifier, m_adapter->bookmark_adapter(m_identifier)}; +} -ListItem Element::as_list_item() const { return {m_document, m_element}; } +ListItem Element::as_list_item() const { + return {m_adapter, m_identifier, m_adapter->list_item_adapter(m_identifier)}; +} -Table Element::as_table() const { return {m_document, m_element}; } +Table Element::as_table() const { + return {m_adapter, m_identifier, m_adapter->table_adapter(m_identifier)}; +} -TableColumn Element::as_table_column() const { return {m_document, m_element}; } +TableColumn Element::as_table_column() const { + return {m_adapter, m_identifier, + m_adapter->table_column_adapter(m_identifier)}; +} -TableRow Element::as_table_row() const { return {m_document, m_element}; } +TableRow Element::as_table_row() const { + return {m_adapter, m_identifier, m_adapter->table_row_adapter(m_identifier)}; +} -TableCell Element::as_table_cell() const { return {m_document, m_element}; } +TableCell Element::as_table_cell() const { + return {m_adapter, m_identifier, m_adapter->table_cell_adapter(m_identifier)}; +} -Frame Element::as_frame() const { return {m_document, m_element}; } +Frame Element::as_frame() const { + return {m_adapter, m_identifier, m_adapter->frame_adapter(m_identifier)}; +} -Rect Element::as_rect() const { return {m_document, m_element}; } +Rect Element::as_rect() const { + return {m_adapter, m_identifier, m_adapter->rect_adapter(m_identifier)}; +} -Line Element::as_line() const { return {m_document, m_element}; } +Line Element::as_line() const { + return {m_adapter, m_identifier, m_adapter->line_adapter(m_identifier)}; +} -Circle Element::as_circle() const { return {m_document, m_element}; } +Circle Element::as_circle() const { + return {m_adapter, m_identifier, m_adapter->circle_adapter(m_identifier)}; +} -CustomShape Element::as_custom_shape() const { return {m_document, m_element}; } +CustomShape Element::as_custom_shape() const { + return {m_adapter, m_identifier, + m_adapter->custom_shape_adapter(m_identifier)}; +} -Image Element::as_image() const { return {m_document, m_element}; } +Image Element::as_image() const { + return {m_adapter, m_identifier, m_adapter->image_adapter(m_identifier)}; +} ElementRange Element::children() const { - return {exists_() - ? ElementIterator(m_document, m_element->first_child(m_document)) - : ElementIterator(), + return {exists_() ? ElementIterator(m_adapter, m_adapter->element_first_child( + m_identifier)) + : ElementIterator(), ElementIterator()}; } ElementIterator::ElementIterator() = default; -ElementIterator::ElementIterator(const internal::abstract::Document *document, - internal::abstract::Element *element) - : m_document{document}, m_element{element} {} - -bool ElementIterator::operator==(const ElementIterator &rhs) const { - return m_element == rhs.m_element; -} - -bool ElementIterator::operator!=(const ElementIterator &rhs) const { - return m_element != rhs.m_element; -} +ElementIterator::ElementIterator( + const internal::abstract::ElementAdapter *adapter, + const ExtendedElementIdentifier identifier) + : m_adapter{adapter}, m_identifier{identifier} {} ElementIterator::reference ElementIterator::operator*() const { - return {m_document, m_element}; + return {m_adapter, m_identifier}; } ElementIterator &ElementIterator::operator++() { if (exists_()) { - m_element = m_element->next_sibling(m_document); + m_identifier = m_adapter->element_next_sibling(m_identifier); } return *this; } @@ -135,17 +170,19 @@ ElementIterator ElementIterator::operator++(int) { if (!exists_()) { return {}; } - return {m_document, m_element->next_sibling(m_document)}; + return {m_adapter, m_adapter->element_next_sibling(m_identifier)}; } -bool ElementIterator::exists_() const { return m_element != nullptr; } +bool ElementIterator::exists_() const { + return m_adapter != nullptr && !m_identifier.is_null(); +} ElementRange::ElementRange() = default; -ElementRange::ElementRange(const ElementIterator begin) : m_begin{begin} {} +ElementRange::ElementRange(const ElementIterator &begin) : m_begin{begin} {} -ElementRange::ElementRange(const ElementIterator begin, - const ElementIterator end) +ElementRange::ElementRange(const ElementIterator &begin, + const ElementIterator &end) : m_begin{begin}, m_end{end} {} ElementIterator ElementRange::begin() const { return m_begin; } @@ -153,346 +190,390 @@ ElementIterator ElementRange::begin() const { return m_begin; } ElementIterator ElementRange::end() const { return m_end; } PageLayout TextRoot::page_layout() const { - return exists_() ? m_element->page_layout(m_document) : PageLayout(); + return exists_() ? m_adapter2->text_root_page_layout(m_identifier) + : PageLayout(); } MasterPage TextRoot::first_master_page() const { - return exists_() - ? MasterPage(m_document, m_element->first_master_page(m_document)) - : MasterPage(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier master_page_id = + m_adapter2->text_root_first_master_page(m_identifier); + return {m_adapter, master_page_id, + m_adapter->master_page_adapter(master_page_id)}; } std::string Slide::name() const { - return exists_() ? m_element->name(m_document) : ""; + return exists_() ? m_adapter2->slide_name(m_identifier) : ""; } PageLayout Slide::page_layout() const { - return exists_() ? m_element->page_layout(m_document) : PageLayout(); + return exists_() ? m_adapter2->slide_page_layout(m_identifier) : PageLayout(); } MasterPage Slide::master_page() const { - return exists_() ? MasterPage(m_document, m_element->master_page(m_document)) - : MasterPage(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier master_page_id = + m_adapter2->slide_master_page(m_identifier); + return {m_adapter, master_page_id, + m_adapter->master_page_adapter(master_page_id)}; } std::string Sheet::name() const { - return exists_() ? m_element->name(m_document) : ""; + return exists_() ? m_adapter2->sheet_name(m_identifier) : ""; } TableDimensions Sheet::dimensions() const { - return exists_() ? m_element->dimensions(m_document) : TableDimensions(); + return exists_() ? m_adapter2->sheet_dimensions(m_identifier) + : TableDimensions(); } TableDimensions Sheet::content(const std::optional range) const { - return exists_() ? m_element->content(m_document, range) : TableDimensions(); + return exists_() ? m_adapter2->sheet_content(m_identifier, range) + : TableDimensions(); } SheetColumn Sheet::column(const std::uint32_t column) const { - return exists_() ? SheetColumn(m_document, m_element, column) : SheetColumn(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier column_id = + m_adapter2->sheet_column(m_identifier, column); + return {m_adapter, column_id, m_adapter->sheet_column_adapter(column_id)}; } SheetRow Sheet::row(const std::uint32_t row) const { - return exists_() ? SheetRow(m_document, m_element, row) : SheetRow(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier row_id = + m_adapter2->sheet_row(m_identifier, row); + return {m_adapter, row_id, m_adapter->sheet_row_adapter(row_id)}; } SheetCell Sheet::cell(const std::uint32_t column, const std::uint32_t row) const { - return exists_() ? SheetCell(m_document, m_element, column, row, - m_element->cell(m_document, column, row)) - : SheetCell(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier cell_id = + m_adapter2->sheet_cell(m_identifier, column, row); + return {m_adapter, cell_id, m_adapter->sheet_cell_adapter(cell_id)}; } ElementRange Sheet::shapes() const { - return exists_() ? ElementRange(ElementIterator( - m_document, m_element->first_shape(m_document))) - : ElementRange(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier first_shape_id = + m_adapter2->sheet_first_shape(m_identifier); + return ElementRange(ElementIterator(m_adapter, first_shape_id)); } -SheetColumn::SheetColumn(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, - const std::uint32_t column) - : TypedElement(document, sheet), m_column{column} {} - TableColumnStyle SheetColumn::style() const { - return exists_() ? m_element->column_style(m_document, m_column) + return exists_() ? m_adapter2->sheet_column_style(m_identifier) : TableColumnStyle(); } -SheetRow::SheetRow(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, const std::uint32_t row) - : TypedElement(document, sheet), m_row{row} {} - TableRowStyle SheetRow::style() const { - return exists_() ? m_element->row_style(m_document, m_row) : TableRowStyle(); + return exists_() ? m_adapter2->sheet_row_style(m_identifier) + : TableRowStyle(); } -SheetCell::SheetCell(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, - const std::uint32_t column, const std::uint32_t row, - internal::abstract::SheetCell *element) - : TypedElement(document, element), m_sheet{sheet}, m_column{column}, - m_row{row} {} - -Sheet SheetCell::sheet() const { return {m_document, m_sheet}; } - -std::uint32_t SheetCell::column() const { return m_column; } +std::uint32_t SheetCell::column() const { + return exists_() ? m_adapter2->sheet_cell_column(m_identifier) : 0; +} -std::uint32_t SheetCell::row() const { return m_row; } +std::uint32_t SheetCell::row() const { + return exists_() ? m_adapter2->sheet_cell_row(m_identifier) : 0; +} bool SheetCell::is_covered() const { - return exists_() ? m_element->is_covered(m_document) : false; + return exists_() && m_adapter2->sheet_cell_is_covered(m_identifier); } TableDimensions SheetCell::span() const { - return exists_() ? m_element->span(m_document) : TableDimensions(1, 1); + return exists_() ? m_adapter2->sheet_cell_span(m_identifier) + : TableDimensions(1, 1); } ValueType SheetCell::value_type() const { - return exists_() ? m_element->value_type(m_document) : ValueType::unknown; + return exists_() ? m_adapter2->sheet_cell_value_type(m_identifier) + : ValueType::unknown; } TableCellStyle SheetCell::style() const { - return m_sheet != nullptr ? m_sheet->cell_style(m_document, m_column, m_row) - : TableCellStyle(); + return exists_() ? m_adapter2->sheet_cell_style(m_identifier) + : TableCellStyle(); } std::string Page::name() const { - return exists_() ? m_element->name(m_document) : ""; + return exists_() ? m_adapter2->page_name(m_identifier) : ""; } PageLayout Page::page_layout() const { - return exists_() ? m_element->page_layout(m_document) : PageLayout(); + return exists_() ? m_adapter2->page_layout(m_identifier) : PageLayout(); } MasterPage Page::master_page() const { - return exists_() ? MasterPage(m_document, m_element->master_page(m_document)) - : MasterPage(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier master_page_id = + m_adapter2->page_master_page(m_identifier); + return {m_adapter, master_page_id, + m_adapter->master_page_adapter(master_page_id)}; } PageLayout MasterPage::page_layout() const { - return exists_() ? m_element->page_layout(m_document) : PageLayout(); + return exists_() ? m_adapter2->master_page_page_layout(m_identifier) + : PageLayout(); } TextStyle LineBreak::style() const { - return exists_() ? m_element->style(m_document) : TextStyle(); + return exists_() ? m_adapter2->line_break_style(m_identifier) : TextStyle(); } ParagraphStyle Paragraph::style() const { - return exists_() ? m_element->style(m_document) : ParagraphStyle(); + return exists_() ? m_adapter2->paragraph_style(m_identifier) + : ParagraphStyle(); } TextStyle Paragraph::text_style() const { - return exists_() ? m_element->text_style(m_document) : TextStyle(); + return exists_() ? m_adapter2->paragraph_text_style(m_identifier) + : TextStyle(); } TextStyle Span::style() const { - return exists_() ? m_element->style(m_document) : TextStyle(); + return exists_() ? m_adapter2->span_style(m_identifier) : TextStyle(); } std::string Text::content() const { - return exists_() ? m_element->content(m_document) : ""; + return exists_() ? m_adapter2->text_content(m_identifier) : ""; } void Text::set_content(const std::string &text) const { - if (exists_()) { - m_element->set_content(m_document, text); + if (!exists_()) { + return; } + m_adapter2->text_set_content(m_identifier, text); } TextStyle Text::style() const { - return exists_() ? m_element->style(m_document) : TextStyle(); + return exists_() ? m_adapter2->text_style(m_identifier) : TextStyle(); } std::string Link::href() const { - return exists_() ? m_element->href(m_document) : ""; + return exists_() ? m_adapter2->link_href(m_identifier) : ""; } std::string Bookmark::name() const { - return exists_() ? m_element->name(m_document) : ""; + return exists_() ? m_adapter2->bookmark_name(m_identifier) : ""; } TextStyle ListItem::style() const { - return exists_() ? m_element->style(m_document) : TextStyle(); + return exists_() ? m_adapter2->list_item_style(m_identifier) : TextStyle(); } TableRow Table::first_row() const { - return exists_() ? TableRow(m_document, m_element->first_row(m_document)) - : TableRow(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier row_id = + m_adapter2->table_first_row(m_identifier); + return {m_adapter, row_id, m_adapter->table_row_adapter(row_id)}; } TableColumn Table::first_column() const { - return exists_() - ? TableColumn(m_document, m_element->first_column(m_document)) - : TableColumn(); + if (!exists_()) { + return {}; + } + const ExtendedElementIdentifier column_id = + m_adapter2->table_first_column(m_identifier); + return {m_adapter, column_id, m_adapter->table_column_adapter(column_id)}; } ElementRange Table::columns() const { - return exists_() ? ElementRange(ElementIterator( - m_document, m_element->first_column(m_document))) - : ElementRange(); + return exists_() + ? ElementRange(ElementIterator( + m_adapter, m_adapter2->table_first_column(m_identifier))) + : ElementRange(); } ElementRange Table::rows() const { return exists_() ? ElementRange(ElementIterator( - m_document, m_element->first_row(m_document))) + m_adapter, m_adapter2->table_first_row(m_identifier))) : ElementRange(); } TableDimensions Table::dimensions() const { - return exists_() ? m_element->dimensions(m_document) : TableDimensions(); + return exists_() ? m_adapter2->table_dimensions(m_identifier) + : TableDimensions(); } TableStyle Table::style() const { - return exists_() ? m_element->style(m_document) : TableStyle(); + return exists_() ? m_adapter2->table_style(m_identifier) : TableStyle(); } TableColumnStyle TableColumn::style() const { - return exists_() ? m_element->style(m_document) : TableColumnStyle(); + return exists_() ? m_adapter2->table_column_style(m_identifier) + : TableColumnStyle(); } TableRowStyle TableRow::style() const { - return exists_() ? m_element->style(m_document) : TableRowStyle(); + return exists_() ? m_adapter2->table_row_style(m_identifier) + : TableRowStyle(); } bool TableCell::is_covered() const { - return exists_() && m_element->is_covered(m_document); + return exists_() && m_adapter2->table_cell_is_covered(m_identifier); } TableDimensions TableCell::span() const { - return exists_() ? m_element->span(m_document) : TableDimensions(); + return exists_() ? m_adapter2->table_cell_span(m_identifier) + : TableDimensions(); } ValueType TableCell::value_type() const { - return exists_() ? m_element->value_type(m_document) : ValueType::string; + return exists_() ? m_adapter2->table_cell_value_type(m_identifier) + : ValueType::string; } TableCellStyle TableCell::style() const { - return exists_() ? m_element->style(m_document) : TableCellStyle(); + return exists_() ? m_adapter2->table_cell_style(m_identifier) + : TableCellStyle(); } AnchorType Frame::anchor_type() const { - return exists_() ? m_element->anchor_type(m_document) + return exists_() ? m_adapter2->frame_anchor_type(m_identifier) : AnchorType::as_char; // TODO default? } std::optional Frame::x() const { - return exists_() ? m_element->x(m_document) : std::optional(); + return exists_() ? m_adapter2->frame_x(m_identifier) + : std::optional(); } std::optional Frame::y() const { - return exists_() ? m_element->y(m_document) : std::optional(); + return exists_() ? m_adapter2->frame_y(m_identifier) + : std::optional(); } std::optional Frame::width() const { - return exists_() ? m_element->width(m_document) + return exists_() ? m_adapter2->frame_width(m_identifier) : std::optional(); } std::optional Frame::height() const { - return exists_() ? m_element->height(m_document) + return exists_() ? m_adapter2->frame_height(m_identifier) : std::optional(); } std::optional Frame::z_index() const { - return exists_() ? m_element->z_index(m_document) + return exists_() ? m_adapter2->frame_z_index(m_identifier) : std::optional(); } GraphicStyle Frame::style() const { - return exists_() ? m_element->style(m_document) : GraphicStyle(); + return exists_() ? m_adapter2->frame_style(m_identifier) : GraphicStyle(); } std::string Rect::x() const { - return exists_() ? m_element->x(m_document) : ""; + return exists_() ? m_adapter2->rect_x(m_identifier) : ""; } std::string Rect::y() const { - return exists_() ? m_element->y(m_document) : ""; + return exists_() ? m_adapter2->rect_y(m_identifier) : ""; } std::string Rect::width() const { - return exists_() ? m_element->width(m_document) : ""; + return exists_() ? m_adapter2->rect_width(m_identifier) : ""; } std::string Rect::height() const { - return exists_() ? m_element->height(m_document) : ""; + return exists_() ? m_adapter2->rect_height(m_identifier) : ""; } GraphicStyle Rect::style() const { - return exists_() ? m_element->style(m_document) : GraphicStyle(); + return exists_() ? m_adapter2->rect_style(m_identifier) : GraphicStyle(); } std::string Line::x1() const { - return exists_() ? m_element->x1(m_document) : ""; + return exists_() ? m_adapter2->line_x1(m_identifier) : ""; } std::string Line::y1() const { - return exists_() ? m_element->y1(m_document) : ""; + return exists_() ? m_adapter2->line_y1(m_identifier) : ""; } std::string Line::x2() const { - return exists_() ? m_element->x2(m_document) : ""; + return exists_() ? m_adapter2->line_x2(m_identifier) : ""; } std::string Line::y2() const { - return exists_() ? m_element->y2(m_document) : ""; + return exists_() ? m_adapter2->line_y2(m_identifier) : ""; } GraphicStyle Line::style() const { - return exists_() ? m_element->style(m_document) : GraphicStyle(); + return exists_() ? m_adapter2->line_style(m_identifier) : GraphicStyle(); } std::string Circle::x() const { - return exists_() ? m_element->x(m_document) : ""; + return exists_() ? m_adapter2->circle_x(m_identifier) : ""; } std::string Circle::y() const { - return exists_() ? m_element->y(m_document) : ""; + return exists_() ? m_adapter2->circle_y(m_identifier) : ""; } std::string Circle::width() const { - return exists_() ? m_element->width(m_document) : ""; + return exists_() ? m_adapter2->circle_width(m_identifier) : ""; } std::string Circle::height() const { - return exists_() ? m_element->height(m_document) : ""; + return exists_() ? m_adapter2->circle_height(m_identifier) : ""; } GraphicStyle Circle::style() const { - return exists_() ? m_element->style(m_document) : GraphicStyle(); + return exists_() ? m_adapter2->circle_style(m_identifier) : GraphicStyle(); } std::optional CustomShape::x() const { - return exists_() ? m_element->x(m_document) : ""; + return exists_() ? m_adapter2->custom_shape_x(m_identifier) : ""; } std::optional CustomShape::y() const { - return exists_() ? m_element->y(m_document) : ""; + return exists_() ? m_adapter2->custom_shape_y(m_identifier) : ""; } std::string CustomShape::width() const { - return exists_() ? m_element->width(m_document) : ""; + return exists_() ? m_adapter2->custom_shape_width(m_identifier) : ""; } std::string CustomShape::height() const { - return exists_() ? m_element->height(m_document) : ""; + return exists_() ? m_adapter2->custom_shape_height(m_identifier) : ""; } GraphicStyle CustomShape::style() const { - return exists_() ? m_element->style(m_document) : GraphicStyle(); + return exists_() ? m_adapter2->custom_shape_style(m_identifier) + : GraphicStyle(); } bool Image::is_internal() const { - return exists_() && m_element->is_internal(m_document); + return exists_() && m_adapter2->image_is_internal(m_identifier); } std::optional Image::file() const { - return exists_() ? m_element->file(m_document) : std::optional(); + return exists_() ? m_adapter2->image_file(m_identifier) + : std::optional(); } std::string Image::href() const { - return exists_() ? m_element->href(m_document) : ""; + return exists_() ? m_adapter2->image_href(m_identifier) : ""; } } // namespace odr diff --git a/src/odr/document_element.hpp b/src/odr/document_element.hpp index e555baec..dcdd0a15 100644 --- a/src/odr/document_element.hpp +++ b/src/odr/document_element.hpp @@ -4,33 +4,37 @@ #include #include +#include + namespace odr::internal::abstract { class Document; -class Element; -class TextRoot; -class Slide; -class Sheet; -class SheetCell; -class Page; -class MasterPage; -class LineBreak; -class Paragraph; -class Span; -class Text; -class Link; -class Bookmark; -class ListItem; -class Table; -class TableColumn; -class TableRow; -class TableCell; -class Frame; -class Rect; -class Line; -class Circle; -class CustomShape; -class Image; +class ElementAdapter; +class TextRootAdapter; +class SlideAdapter; +class PageAdapter; +class SheetAdapter; +class SheetColumnAdapter; +class SheetRowAdapter; +class SheetCellAdapter; +class MasterPageAdapter; +class LineBreakAdapter; +class ParagraphAdapter; +class SpanAdapter; +class TextAdapter; +class LinkAdapter; +class BookmarkAdapter; +class ListItemAdapter; +class TableAdapter; +class TableColumnAdapter; +class TableRowAdapter; +class TableCellAdapter; +class FrameAdapter; +class RectAdapter; +class LineAdapter; +class CircleAdapter; +class CustomShapeAdapter; +class ImageAdapter; } // namespace odr::internal::abstract namespace odr { @@ -136,10 +140,8 @@ enum class ValueType { class Element { public: Element(); - Element(const internal::abstract::Document *, internal::abstract::Element *); - - bool operator==(const Element &rhs) const; - bool operator!=(const Element &rhs) const; + Element(const internal::abstract::ElementAdapter *adapter, + ExtendedElementIdentifier identifier); explicit operator bool() const; @@ -178,8 +180,12 @@ class Element { [[nodiscard]] Image as_image() const; protected: - const internal::abstract::Document *m_document{nullptr}; - internal::abstract::Element *m_element{nullptr}; + const internal::abstract::ElementAdapter *m_adapter{nullptr}; + ExtendedElementIdentifier m_identifier; + + friend bool operator==(const Element &lhs, const Element &rhs) { + return lhs.m_identifier == rhs.m_identifier; + } [[nodiscard]] bool exists_() const; }; @@ -194,11 +200,8 @@ class ElementIterator { using iterator_category = std::forward_iterator_tag; ElementIterator(); - ElementIterator(const internal::abstract::Document *, - internal::abstract::Element *); - - bool operator==(const ElementIterator &rhs) const; - bool operator!=(const ElementIterator &rhs) const; + ElementIterator(const internal::abstract::ElementAdapter *adapter, + ExtendedElementIdentifier identifier); reference operator*() const; @@ -206,8 +209,13 @@ class ElementIterator { ElementIterator operator++(int); private: - const internal::abstract::Document *m_document{nullptr}; - internal::abstract::Element *m_element{nullptr}; + const internal::abstract::ElementAdapter *m_adapter{nullptr}; + ExtendedElementIdentifier m_identifier; + + friend bool operator==(const ElementIterator &lhs, + const ElementIterator &rhs) { + return lhs.m_identifier == rhs.m_identifier; + } [[nodiscard]] bool exists_() const; }; @@ -216,8 +224,8 @@ class ElementIterator { class ElementRange { public: ElementRange(); - explicit ElementRange(ElementIterator begin); - ElementRange(ElementIterator begin, ElementIterator end); + explicit ElementRange(const ElementIterator &begin); + ElementRange(const ElementIterator &begin, const ElementIterator &end); [[nodiscard]] ElementIterator begin() const; [[nodiscard]] ElementIterator end() const; @@ -228,26 +236,25 @@ class ElementRange { }; /// @brief Represents a typed element in a document. -template class TypedElement : public Element { +template class ElementBase : public Element { public: - TypedElement() = default; - TypedElement(const internal::abstract::Document *document, T *element) - : Element(document, element), m_element{element} {} - TypedElement(const internal::abstract::Document *document, - internal::abstract::Element *element) - : Element(document, dynamic_cast(element)), - m_element{dynamic_cast(element)} {} + ElementBase() = default; + ElementBase(const internal::abstract::ElementAdapter *adapter, + const ExtendedElementIdentifier identifier, const T *adapter2) + : Element(adapter, identifier), m_adapter2{adapter2} {} protected: - T *m_element; + const T *m_adapter2{nullptr}; - [[nodiscard]] bool exists_() const { return m_element != nullptr; } + [[nodiscard]] bool exists_() const { + return Element::exists_() && m_adapter2 != nullptr; + } }; /// @brief Represents a root element in a document. -class TextRoot final : public TypedElement { +class TextRoot final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] PageLayout page_layout() const; @@ -255,9 +262,9 @@ class TextRoot final : public TypedElement { }; /// @brief Represents a slide element in a document. -class Slide final : public TypedElement { +class Slide final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string name() const; @@ -267,9 +274,9 @@ class Slide final : public TypedElement { }; /// @brief Represents a sheet element in a document. -class Sheet final : public TypedElement { +class Sheet final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string name() const; @@ -285,40 +292,28 @@ class Sheet final : public TypedElement { }; /// @brief Represents a sheet column element in a document. -class SheetColumn final : public TypedElement { +class SheetColumn final + : public ElementBase { public: - SheetColumn() = default; - SheetColumn(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, std::uint32_t column); + using ElementBase::ElementBase; [[nodiscard]] TableColumnStyle style() const; - -private: - std::uint32_t m_column{}; }; /// @brief Represents a sheet row element in a document. -class SheetRow final : public TypedElement { +class SheetRow final : public ElementBase { public: - SheetRow() = default; - SheetRow(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, std::uint32_t row); + using ElementBase::ElementBase; [[nodiscard]] TableRowStyle style() const; - -private: - std::uint32_t m_row{}; }; /// @brief Represents a sheet cell element in a document. -class SheetCell final : public TypedElement { +class SheetCell final + : public ElementBase { public: - SheetCell() = default; - SheetCell(const internal::abstract::Document *document, - internal::abstract::Sheet *sheet, std::uint32_t column, - std::uint32_t row, internal::abstract::SheetCell *element); + using ElementBase::ElementBase; - [[nodiscard]] Sheet sheet() const; [[nodiscard]] std::uint32_t column() const; [[nodiscard]] std::uint32_t row() const; [[nodiscard]] bool is_covered() const; @@ -326,17 +321,12 @@ class SheetCell final : public TypedElement { [[nodiscard]] ValueType value_type() const; [[nodiscard]] TableCellStyle style() const; - -private: - internal::abstract::Sheet *m_sheet{}; - std::uint32_t m_column{}; - std::uint32_t m_row{}; }; /// @brief Represents a page element in a document. -class Page final : public TypedElement { +class Page final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string name() const; @@ -346,42 +336,45 @@ class Page final : public TypedElement { }; /// @brief Represents a master page element in a document. -class MasterPage final : public TypedElement { +class MasterPage final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] PageLayout page_layout() const; }; /// @brief Represents a line break element in a document. -class LineBreak final : public TypedElement { +class LineBreak final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TextStyle style() const; }; /// @brief Represents a paragraph element in a document. -class Paragraph final : public TypedElement { +class Paragraph final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] ParagraphStyle style() const; [[nodiscard]] TextStyle text_style() const; }; /// @brief Represents a span element in a document. -class Span final : public TypedElement { +class Span final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TextStyle style() const; }; /// @brief Represents a text element in a document. -class Text final : public TypedElement { +class Text final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string content() const; void set_content(const std::string &text) const; @@ -390,33 +383,33 @@ class Text final : public TypedElement { }; /// @brief Represents a link element in a document. -class Link final : public TypedElement { +class Link final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string href() const; }; /// @brief Represents a bookmark element in a document. -class Bookmark final : public TypedElement { +class Bookmark final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string name() const; }; /// @brief Represents a list item element in a document. -class ListItem final : public TypedElement { +class ListItem final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TextStyle style() const; }; /// @brief Represents a table element in a document. -class Table final : public TypedElement { +class Table final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TableRow first_row() const; [[nodiscard]] TableColumn first_column() const; @@ -430,25 +423,27 @@ class Table final : public TypedElement { }; /// @brief Represents a table column element in a document. -class TableColumn final : public TypedElement { +class TableColumn final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TableColumnStyle style() const; }; /// @brief Represents a table row element in a document. -class TableRow final : public TypedElement { +class TableRow final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] TableRowStyle style() const; }; /// @brief Represents a table cell element in a document. -class TableCell final : public TypedElement { +class TableCell final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] bool is_covered() const; [[nodiscard]] TableDimensions span() const; @@ -458,9 +453,9 @@ class TableCell final : public TypedElement { }; /// @brief Represents a frame element in a document. -class Frame final : public TypedElement { +class Frame final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] AnchorType anchor_type() const; [[nodiscard]] std::optional x() const; @@ -473,9 +468,9 @@ class Frame final : public TypedElement { }; /// @brief Represents a rectangle element in a document. -class Rect final : public TypedElement { +class Rect final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string x() const; [[nodiscard]] std::string y() const; @@ -486,9 +481,9 @@ class Rect final : public TypedElement { }; /// @brief Represents a line element in a document. -class Line final : public TypedElement { +class Line final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string x1() const; [[nodiscard]] std::string y1() const; @@ -499,9 +494,9 @@ class Line final : public TypedElement { }; /// @brief Represents a circle element in a document. -class Circle final : public TypedElement { +class Circle final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::string x() const; [[nodiscard]] std::string y() const; @@ -512,9 +507,10 @@ class Circle final : public TypedElement { }; /// @brief Represents a custom shape element in a document. -class CustomShape final : public TypedElement { +class CustomShape final + : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] std::optional x() const; [[nodiscard]] std::optional y() const; @@ -525,9 +521,9 @@ class CustomShape final : public TypedElement { }; /// @brief Represents an image element in a document. -class Image final : public TypedElement { +class Image final : public ElementBase { public: - using TypedElement::TypedElement; + using ElementBase::ElementBase; [[nodiscard]] bool is_internal() const; [[nodiscard]] std::optional file() const; diff --git a/src/odr/document_element_identifier.hpp b/src/odr/document_element_identifier.hpp new file mode 100644 index 00000000..e7de158c --- /dev/null +++ b/src/odr/document_element_identifier.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include + +namespace odr { + +using ElementIdentifier = std::uint64_t; + +static constexpr ElementIdentifier null_element_id{0}; + +class ExtendedElementIdentifier { +public: + using Extra = std::uint32_t; + + static constexpr Extra no_extra{0}; + + static constexpr ExtendedElementIdentifier null() noexcept { return {}; } + static constexpr ExtendedElementIdentifier + make_column(const ElementIdentifier element_id, + const std::uint32_t column) noexcept { + return ExtendedElementIdentifier{element_id, column + 1, no_extra}; + } + static constexpr ExtendedElementIdentifier + make_row(const ElementIdentifier element_id, + const std::uint32_t row) noexcept { + return ExtendedElementIdentifier{element_id, no_extra, row + 1}; + } + static constexpr ExtendedElementIdentifier + make_cell(const ElementIdentifier element_id, const std::uint32_t column, + const std::uint32_t row) noexcept { + return ExtendedElementIdentifier{element_id, column + 1, row + 1}; + } + + constexpr ExtendedElementIdentifier() noexcept = default; + + explicit constexpr ExtendedElementIdentifier( + const ElementIdentifier element_id, const Extra extra0 = no_extra, + const Extra extra1 = no_extra) noexcept + : m_element_id{element_id}, m_extra0{extra0}, m_extra1{extra1} {} + + [[nodiscard]] constexpr ElementIdentifier element_id() const noexcept { + return m_element_id; + } + [[nodiscard]] constexpr Extra extra0() const noexcept { return m_extra0; } + [[nodiscard]] constexpr Extra extra1() const noexcept { return m_extra1; } + + [[nodiscard]] constexpr bool is_null() const noexcept { + return m_element_id == null_element_id; + } + [[nodiscard]] constexpr bool has_extra0() const noexcept { + return m_extra0 != no_extra; + } + [[nodiscard]] constexpr bool has_extra1() const noexcept { + return m_extra1 != no_extra; + } + + [[nodiscard]] constexpr bool has_column() const noexcept { + return has_extra0() && !has_extra1(); + } + [[nodiscard]] constexpr bool has_row() const noexcept { + return !has_extra0() && has_extra1(); + } + [[nodiscard]] constexpr bool has_cell() const noexcept { + return has_extra0() && has_extra1(); + } + + [[nodiscard]] std::uint32_t column() const noexcept { return m_extra0 - 1; } + [[nodiscard]] std::uint32_t row() const noexcept { return m_extra1 - 1; } + [[nodiscard]] std::pair cell() const noexcept { + return {column(), row()}; + } + + [[nodiscard]] ExtendedElementIdentifier without_extra() const noexcept { + return ExtendedElementIdentifier(m_element_id); + } + +private: + ElementIdentifier m_element_id{null_element_id}; + Extra m_extra0{no_extra}; + Extra m_extra1{no_extra}; + + friend constexpr bool + operator==(const ExtendedElementIdentifier &lhs, + const ExtendedElementIdentifier &rhs) noexcept { + return lhs.m_element_id == rhs.m_element_id && + lhs.m_extra0 == rhs.m_extra0 && lhs.m_extra1 == rhs.m_extra1; + } + + friend constexpr std::strong_ordering + operator<=>(const ExtendedElementIdentifier &a, + const ExtendedElementIdentifier &b) noexcept { + if (const std::strong_ordering cmp = a.m_element_id <=> b.m_element_id; + cmp != 0) { + return cmp; + } + if (const std::strong_ordering cmp = a.m_extra0 <=> b.m_extra0; cmp != 0) { + return cmp; + } + return a.m_extra1 <=> b.m_extra1; + } +}; + +} // namespace odr diff --git a/src/odr/internal/abstract/document.hpp b/src/odr/internal/abstract/document.hpp index fb8e0e4a..88847f40 100644 --- a/src/odr/internal/abstract/document.hpp +++ b/src/odr/internal/abstract/document.hpp @@ -1,10 +1,9 @@ #pragma once -#include - #include namespace odr { +class ExtendedElementIdentifier; class File; enum class FileType; enum class DocumentType; @@ -16,7 +15,7 @@ class Path; namespace odr::internal::abstract { class ReadableFilesystem; -class Element; +class ElementAdapter; class Document { public: @@ -47,7 +46,9 @@ class Document { as_filesystem() const noexcept = 0; /// \return cursor to the root element of the document. - [[nodiscard]] virtual Element *root_element() const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier root_element() const = 0; + + [[nodiscard]] virtual const ElementAdapter *element_adapter() const = 0; }; } // namespace odr::internal::abstract diff --git a/src/odr/internal/abstract/document_element.hpp b/src/odr/internal/abstract/document_element.hpp index 477ddad3..27990d0d 100644 --- a/src/odr/internal/abstract/document_element.hpp +++ b/src/odr/internal/abstract/document_element.hpp @@ -2,294 +2,437 @@ #include +#include #include #include -#ifdef _MSC_VER -#pragma warning(disable : 4250) -#endif - namespace odr { -class File; - enum class ElementType; -struct TextStyle; -struct ParagraphStyle; -struct TableStyle; -struct TableColumnStyle; -struct TableRowStyle; -struct TableCellStyle; -struct GraphicStyle; -struct PageLayout; -struct TableDimensions; +class ExtendedElementIdentifier; +class File; } // namespace odr namespace odr::internal::abstract { -class Document; -class MasterPage; - -class Element { +class TextRootAdapter; +class SlideAdapter; +class PageAdapter; +class SheetAdapter; +class SheetColumnAdapter; +class SheetRowAdapter; +class SheetCellAdapter; +class MasterPageAdapter; +class LineBreakAdapter; +class ParagraphAdapter; +class SpanAdapter; +class TextAdapter; +class LinkAdapter; +class BookmarkAdapter; +class ListItemAdapter; +class TableAdapter; +class TableColumnAdapter; +class TableRowAdapter; +class TableCellAdapter; +class FrameAdapter; +class RectAdapter; +class LineAdapter; +class CircleAdapter; +class CustomShapeAdapter; +class ImageAdapter; + +class ElementAdapter { public: - virtual ~Element() = default; + virtual ~ElementAdapter() = default; + + [[nodiscard]] virtual ElementType + element_type(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual ExtendedElementIdentifier + element_parent(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + element_first_child(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + element_last_child(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + element_previous_sibling(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + element_next_sibling(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual bool + element_is_editable(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual const TextRootAdapter * + text_root_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SlideAdapter * + slide_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const PageAdapter * + page_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetAdapter * + sheet_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetColumnAdapter * + sheet_column_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetRowAdapter * + sheet_row_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SheetCellAdapter * + sheet_cell_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const MasterPageAdapter * + master_page_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LineBreakAdapter * + line_break_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ParagraphAdapter * + paragraph_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const SpanAdapter * + span_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TextAdapter * + text_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LinkAdapter * + link_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const BookmarkAdapter * + bookmark_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ListItemAdapter * + list_item_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableAdapter * + table_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableColumnAdapter * + table_column_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableRowAdapter * + table_row_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const TableCellAdapter * + table_cell_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const FrameAdapter * + frame_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const RectAdapter * + rect_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const LineAdapter * + line_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const CircleAdapter * + circle_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const CustomShapeAdapter * + custom_shape_adapter(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual const ImageAdapter * + image_adapter(ExtendedElementIdentifier element_id) const = 0; +}; - [[nodiscard]] virtual ElementType type(const Document *) const = 0; +class TextRootAdapter { +public: + virtual ~TextRootAdapter() = default; - [[nodiscard]] virtual Element *parent(const Document *) const = 0; - [[nodiscard]] virtual Element *first_child(const Document *) const = 0; - [[nodiscard]] virtual Element *last_child(const Document *) const = 0; - [[nodiscard]] virtual Element *previous_sibling(const Document *) const = 0; - [[nodiscard]] virtual Element *next_sibling(const Document *) const = 0; + [[nodiscard]] virtual PageLayout + text_root_page_layout(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual bool is_editable(const Document *document) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + text_root_first_master_page(ExtendedElementIdentifier element_id) const = 0; }; -class TextRoot : public virtual Element { +class SlideAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::root; - } + virtual ~SlideAdapter() = default; + + [[nodiscard]] virtual PageLayout + slide_page_layout(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual PageLayout page_layout(const Document *) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + slide_master_page(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual Element *first_master_page(const Document *) const = 0; + [[nodiscard]] virtual std::string + slide_name(ExtendedElementIdentifier element_id) const = 0; }; -class Slide : public virtual Element { +class PageAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::slide; - } + virtual ~PageAdapter() = default; - [[nodiscard]] virtual PageLayout page_layout(const Document *) const = 0; + [[nodiscard]] virtual PageLayout + page_layout(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual Element *master_page(const Document *) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + page_master_page(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual std::string name(const Document *) const = 0; + [[nodiscard]] virtual std::string + page_name(ExtendedElementIdentifier element_id) const = 0; }; -class Page : public virtual Element { +class SheetAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::page; - } + virtual ~SheetAdapter() = default; + + [[nodiscard]] virtual std::string + sheet_name(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableDimensions + sheet_dimensions(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + sheet_content(ExtendedElementIdentifier element_id, + std::optional range) const = 0; + + [[nodiscard]] virtual ExtendedElementIdentifier + sheet_column(ExtendedElementIdentifier element_id, + std::uint32_t column) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + sheet_row(ExtendedElementIdentifier element_id, std::uint32_t row) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + sheet_cell(ExtendedElementIdentifier element_id, std::uint32_t column, + std::uint32_t row) const = 0; + + [[nodiscard]] virtual ExtendedElementIdentifier + sheet_first_shape(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableStyle + sheet_style(ExtendedElementIdentifier element_id) const = 0; +}; - [[nodiscard]] virtual PageLayout page_layout(const Document *) const = 0; +class SheetColumnAdapter { +public: + virtual ~SheetColumnAdapter() = default; - [[nodiscard]] virtual Element *master_page(const Document *) const = 0; + [[nodiscard]] virtual TableColumnStyle + sheet_column_style(ExtendedElementIdentifier element_id) const = 0; +}; - [[nodiscard]] virtual std::string name(const Document *) const = 0; +class SheetRowAdapter { +public: + virtual ~SheetRowAdapter() = default; + + [[nodiscard]] virtual TableRowStyle + sheet_row_style(ExtendedElementIdentifier element_id) const = 0; +}; + +class SheetCellAdapter { +public: + virtual ~SheetCellAdapter() = default; + + [[nodiscard]] virtual std::uint32_t + sheet_cell_column(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::uint32_t + sheet_cell_row(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual bool + sheet_cell_is_covered(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + sheet_cell_span(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ValueType + sheet_cell_value_type(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual TableCellStyle + sheet_cell_style(ExtendedElementIdentifier element_id) const = 0; }; -class MasterPage : public virtual Element { +class MasterPageAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::master_page; - } + virtual ~MasterPageAdapter() = default; - [[nodiscard]] virtual PageLayout page_layout(const Document *) const = 0; + [[nodiscard]] virtual PageLayout + master_page_page_layout(ExtendedElementIdentifier element_id) const = 0; }; -class LineBreak : public virtual Element { +class LineBreakAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::line_break; - } + virtual ~LineBreakAdapter() = default; - [[nodiscard]] virtual TextStyle style(const Document *) const = 0; + [[nodiscard]] virtual TextStyle + line_break_style(ExtendedElementIdentifier element_id) const = 0; }; -class Paragraph : public virtual Element { +class ParagraphAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::paragraph; - } + virtual ~ParagraphAdapter() = default; - [[nodiscard]] virtual ParagraphStyle style(const Document *) const = 0; - [[nodiscard]] virtual TextStyle text_style(const Document *) const = 0; + [[nodiscard]] virtual ParagraphStyle + paragraph_style(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TextStyle + paragraph_text_style(ExtendedElementIdentifier element_id) const = 0; }; -class Span : public virtual Element { +class SpanAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::span; - } + virtual ~SpanAdapter() = default; - [[nodiscard]] virtual TextStyle style(const Document *document) const = 0; + [[nodiscard]] virtual TextStyle + span_style(ExtendedElementIdentifier element_id) const = 0; }; -class Text : public virtual Element { +class TextAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::text; - } + virtual ~TextAdapter() = default; - [[nodiscard]] virtual std::string content(const Document *) const = 0; - virtual void set_content(const Document *, const std::string &text) = 0; + [[nodiscard]] virtual std::string + text_content(ExtendedElementIdentifier element_id) const = 0; + virtual void text_set_content(ExtendedElementIdentifier element_id, + const std::string &text) const = 0; - [[nodiscard]] virtual TextStyle style(const Document *) const = 0; + [[nodiscard]] virtual TextStyle + text_style(ExtendedElementIdentifier element_id) const = 0; }; -class Link : public virtual Element { +class LinkAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::link; - } + virtual ~LinkAdapter() = default; - [[nodiscard]] virtual std::string href(const Document *) const = 0; + [[nodiscard]] virtual std::string + link_href(ExtendedElementIdentifier element_id) const = 0; }; -class Bookmark : public virtual Element { +class BookmarkAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::bookmark; - } + virtual ~BookmarkAdapter() = default; - [[nodiscard]] virtual std::string name(const Document *) const = 0; + [[nodiscard]] virtual std::string + bookmark_name(ExtendedElementIdentifier element_id) const = 0; }; -class ListItem : public virtual Element { +class ListItemAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::list_item; - } + virtual ~ListItemAdapter() = default; - [[nodiscard]] virtual TextStyle style(const Document *) const = 0; + [[nodiscard]] virtual TextStyle + list_item_style(ExtendedElementIdentifier element_id) const = 0; }; -class Table : public virtual Element { +class TableAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::table; - } + virtual ~TableAdapter() = default; - [[nodiscard]] virtual TableDimensions dimensions(const Document *) const = 0; + [[nodiscard]] virtual TableDimensions + table_dimensions(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual Element *first_column(const Document *) const = 0; - [[nodiscard]] virtual Element *first_row(const Document *) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + table_first_column(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ExtendedElementIdentifier + table_first_row(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableStyle style(const Document *) const = 0; + [[nodiscard]] virtual TableStyle + table_style(ExtendedElementIdentifier element_id) const = 0; }; -class TableColumn : public virtual Element { +class TableColumnAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::table_column; - } + virtual ~TableColumnAdapter() = default; - [[nodiscard]] virtual TableColumnStyle style(const Document *) const = 0; + [[nodiscard]] virtual TableColumnStyle + table_column_style(ExtendedElementIdentifier element_id) const = 0; }; -class TableRow : public virtual Element { +class TableRowAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::table_row; - } + virtual ~TableRowAdapter() = default; - [[nodiscard]] virtual TableRowStyle style(const Document *) const = 0; + [[nodiscard]] virtual TableRowStyle + table_row_style(ExtendedElementIdentifier element_id) const = 0; }; -class TableCell : public virtual Element { +class TableCellAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::table_cell; - } + virtual ~TableCellAdapter() = default; - [[nodiscard]] virtual bool is_covered(const Document *) const = 0; - [[nodiscard]] virtual TableDimensions span(const Document *) const = 0; - [[nodiscard]] virtual ValueType value_type(const Document *) const = 0; + [[nodiscard]] virtual bool + table_cell_is_covered(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual TableDimensions + table_cell_span(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual ValueType + table_cell_value_type(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual TableCellStyle style(const Document *) const = 0; + [[nodiscard]] virtual TableCellStyle + table_cell_style(ExtendedElementIdentifier element_id) const = 0; }; -class Frame : public virtual Element { +class FrameAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::frame; - } + virtual ~FrameAdapter() = default; - [[nodiscard]] virtual AnchorType anchor_type(const Document *) const = 0; + [[nodiscard]] virtual AnchorType + frame_anchor_type(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - x(const Document *) const = 0; + frame_x(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - y(const Document *) const = 0; + frame_y(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - width(const Document *) const = 0; + frame_width(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - height(const Document *) const = 0; + frame_height(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - z_index(const Document *) const = 0; + frame_z_index(ExtendedElementIdentifier element_id) const = 0; - [[nodiscard]] virtual GraphicStyle style(const Document *) const = 0; + [[nodiscard]] virtual GraphicStyle + frame_style(ExtendedElementIdentifier element_id) const = 0; }; -class Rect : public virtual Element { +class RectAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::rect; - } - - [[nodiscard]] virtual std::string x(const Document *) const = 0; - [[nodiscard]] virtual std::string y(const Document *) const = 0; - [[nodiscard]] virtual std::string width(const Document *) const = 0; - [[nodiscard]] virtual std::string height(const Document *) const = 0; - - [[nodiscard]] virtual GraphicStyle style(const Document *) const = 0; + virtual ~RectAdapter() = default; + + [[nodiscard]] virtual std::string + rect_x(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_y(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_width(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + rect_height(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + rect_style(ExtendedElementIdentifier element_id) const = 0; }; -class Line : public virtual Element { +class LineAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::line; - } - - [[nodiscard]] virtual std::string x1(const Document *) const = 0; - [[nodiscard]] virtual std::string y1(const Document *) const = 0; - [[nodiscard]] virtual std::string x2(const Document *) const = 0; - [[nodiscard]] virtual std::string y2(const Document *) const = 0; - - [[nodiscard]] virtual GraphicStyle style(const Document *) const = 0; + virtual ~LineAdapter() = default; + + [[nodiscard]] virtual std::string + line_x1(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_y1(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_x2(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + line_y2(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + line_style(ExtendedElementIdentifier element_id) const = 0; }; -class Circle : public virtual Element { +class CircleAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::circle; - } - - [[nodiscard]] virtual std::string x(const Document *) const = 0; - [[nodiscard]] virtual std::string y(const Document *) const = 0; - [[nodiscard]] virtual std::string width(const Document *) const = 0; - [[nodiscard]] virtual std::string height(const Document *) const = 0; - - [[nodiscard]] virtual GraphicStyle style(const Document *) const = 0; + virtual ~CircleAdapter() = default; + + [[nodiscard]] virtual std::string + circle_x(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_y(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_width(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + circle_height(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + circle_style(ExtendedElementIdentifier element_id) const = 0; }; -class CustomShape : public virtual Element { +class CustomShapeAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::custom_shape; - } + virtual ~CustomShapeAdapter() = default; [[nodiscard]] virtual std::optional - x(const Document *) const = 0; + custom_shape_x(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - y(const Document *) const = 0; - [[nodiscard]] virtual std::string width(const Document *) const = 0; - [[nodiscard]] virtual std::string height(const Document *) const = 0; - - [[nodiscard]] virtual GraphicStyle style(const Document *) const = 0; + custom_shape_y(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + custom_shape_width(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + custom_shape_height(ExtendedElementIdentifier element_id) const = 0; + + [[nodiscard]] virtual GraphicStyle + custom_shape_style(ExtendedElementIdentifier element_id) const = 0; }; -class Image : public virtual Element { +class ImageAdapter { public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::image; - } + virtual ~ImageAdapter() = default; - [[nodiscard]] virtual bool is_internal(const Document *) const = 0; + [[nodiscard]] virtual bool + image_is_internal(ExtendedElementIdentifier element_id) const = 0; [[nodiscard]] virtual std::optional - file(const Document *) const = 0; - [[nodiscard]] virtual std::string href(const Document *) const = 0; + image_file(ExtendedElementIdentifier element_id) const = 0; + [[nodiscard]] virtual std::string + image_href(ExtendedElementIdentifier element_id) const = 0; }; } // namespace odr::internal::abstract diff --git a/src/odr/internal/abstract/sheet_element.hpp b/src/odr/internal/abstract/sheet_element.hpp deleted file mode 100644 index 8049c945..00000000 --- a/src/odr/internal/abstract/sheet_element.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include - -namespace odr::internal::abstract { -class SheetCell; - -class Sheet : public virtual Element { -public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::sheet; - } - - [[nodiscard]] virtual std::string name(const Document *) const = 0; - - [[nodiscard]] virtual TableDimensions dimensions(const Document *) const = 0; - [[nodiscard]] virtual TableDimensions - content(const Document *, std::optional range) const = 0; - - [[nodiscard]] virtual SheetCell *cell(const Document *, std::uint32_t column, - std::uint32_t row) const = 0; - - [[nodiscard]] virtual Element *first_shape(const Document *) const = 0; - - [[nodiscard]] virtual TableStyle style(const Document *) const = 0; - [[nodiscard]] virtual TableColumnStyle - column_style(const Document *, std::uint32_t column) const = 0; - [[nodiscard]] virtual TableRowStyle row_style(const Document *, - std::uint32_t row) const = 0; - [[nodiscard]] virtual TableCellStyle cell_style(const Document *, - std::uint32_t column, - std::uint32_t row) const = 0; -}; - -class SheetCell : public virtual Element { -public: - [[nodiscard]] ElementType type(const Document *) const override { - return ElementType::sheet_cell; - } - - [[nodiscard]] virtual bool is_covered(const Document *) const = 0; - [[nodiscard]] virtual TableDimensions span(const Document *) const = 0; - [[nodiscard]] virtual ValueType value_type(const Document *) const = 0; - - [[nodiscard]] virtual TableCellStyle style(const Document *) const = 0; -}; - -} // namespace odr::internal::abstract diff --git a/src/odr/internal/common/document.cpp b/src/odr/internal/common/document.cpp index 8fac6c41..0f322992 100644 --- a/src/odr/internal/common/document.cpp +++ b/src/odr/internal/common/document.cpp @@ -1,15 +1,17 @@ #include +#include +#include #include -#include - namespace odr::internal { Document::Document(const FileType file_type, const DocumentType document_type, std::shared_ptr files) : m_file_type{file_type}, m_document_type{document_type}, - m_filesystem{std::move(files)} {} + m_files{std::move(files)} {} + +Document::~Document() = default; FileType Document::file_type() const noexcept { return m_file_type; } @@ -19,7 +21,15 @@ DocumentType Document::document_type() const noexcept { std::shared_ptr Document::as_filesystem() const noexcept { - return m_filesystem; + return m_files; +} + +ExtendedElementIdentifier Document::root_element() const { + return m_root_element; +} + +const abstract::ElementAdapter *Document::element_adapter() const { + return m_element_adapter.get(); } } // namespace odr::internal diff --git a/src/odr/internal/common/document.hpp b/src/odr/internal/common/document.hpp index df489a80..6dd24f96 100644 --- a/src/odr/internal/common/document.hpp +++ b/src/odr/internal/common/document.hpp @@ -1,20 +1,21 @@ #pragma once +#include #include -#include +#include namespace odr::internal::abstract { class ReadableFilesystem; } // namespace odr::internal::abstract namespace odr::internal { -class Element; class Document : public abstract::Document { public: Document(FileType file_type, DocumentType document_type, std::shared_ptr files); + ~Document() override; [[nodiscard]] FileType file_type() const noexcept final; [[nodiscard]] DocumentType document_type() const noexcept final; @@ -22,32 +23,19 @@ class Document : public abstract::Document { [[nodiscard]] std::shared_ptr as_filesystem() const noexcept final; + [[nodiscard]] ExtendedElementIdentifier root_element() const override; + + [[nodiscard]] const abstract::ElementAdapter * + element_adapter() const override; + protected: FileType m_file_type; DocumentType m_document_type; - std::shared_ptr m_filesystem; + std::shared_ptr m_files; - friend class Element; -}; - -template class TemplateDocument : public Document { -public: - TemplateDocument(FileType file_type, const DocumentType document_type, - std::shared_ptr filesystem) - : Document(file_type, document_type, std::move(filesystem)) {} - - [[nodiscard]] abstract::Element *root_element() const final { - return m_root_element; - } - - void register_element_(std::unique_ptr element) { - m_elements.push_back(std::move(element)); - } - -protected: - std::vector> m_elements; - element_t *m_root_element{}; + ExtendedElementIdentifier m_root_element; + std::unique_ptr m_element_adapter; }; } // namespace odr::internal diff --git a/src/odr/internal/common/document_element.cpp b/src/odr/internal/common/document_element.cpp deleted file mode 100644 index 12f18c67..00000000 --- a/src/odr/internal/common/document_element.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include - -namespace odr::internal { - -abstract::Element *Element::parent(const abstract::Document *) const { - return m_parent; -} - -abstract::Element *Element::first_child(const abstract::Document *) const { - return m_first_child; -} - -abstract::Element *Element::last_child(const abstract::Document *) const { - return m_last_child; -} - -abstract::Element *Element::previous_sibling(const abstract::Document *) const { - return m_previous_sibling; -} - -abstract::Element *Element::next_sibling(const abstract::Document *) const { - return m_next_sibling; -} - -void Element::append_child_(Element *element) { - element->m_previous_sibling = m_last_child; - element->m_parent = this; - if (m_last_child == nullptr) { - m_first_child = element; - } else { - m_last_child->m_next_sibling = element; - } - m_last_child = element; -} - -abstract::Element *Table::first_column(const abstract::Document *) const { - return m_first_column; -} - -abstract::Element *Table::first_row(const abstract::Document *) const { - return m_first_child; -} - -void Table::append_column_(Element *element) { - element->m_previous_sibling = m_last_column; - element->m_parent = this; - if (m_last_column == nullptr) { - m_first_column = element; - } else { - m_last_column->m_next_sibling = element; - } - m_last_column = element; -} - -void Table::append_row_(Element *element) { append_child_(element); } - -} // namespace odr::internal diff --git a/src/odr/internal/common/document_element.hpp b/src/odr/internal/common/document_element.hpp deleted file mode 100644 index 2734c330..00000000 --- a/src/odr/internal/common/document_element.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include - -#include - -namespace odr::internal::abstract { -class Document; -} // namespace odr::internal::abstract - -namespace odr::internal { - -class Element : public virtual abstract::Element { -public: - [[nodiscard]] abstract::Element * - parent(const abstract::Document *) const override; - [[nodiscard]] abstract::Element * - first_child(const abstract::Document *) const override; - [[nodiscard]] abstract::Element * - last_child(const abstract::Document *) const override; - [[nodiscard]] abstract::Element * - previous_sibling(const abstract::Document *) const override; - [[nodiscard]] abstract::Element * - next_sibling(const abstract::Document *) const override; - - void append_child_(Element *element); - - template - static const document_t &document_(const abstract::Document *document) { - const auto *cast = dynamic_cast(document); - if (cast == nullptr) { - throw std::runtime_error("unknown document type"); - } - return *cast; - } - - Element *m_parent{}; - Element *m_first_child{}; - Element *m_last_child{}; - Element *m_previous_sibling{}; - Element *m_next_sibling{}; -}; - -class Table : public virtual Element, public abstract::Table { -public: - [[nodiscard]] abstract::Element * - first_column(const abstract::Document *) const final; - [[nodiscard]] abstract::Element * - first_row(const abstract::Document *) const final; - - void append_column_(Element *element); - void append_row_(Element *element); - - Element *m_first_column{}; - Element *m_last_column{}; -}; - -} // namespace odr::internal diff --git a/src/odr/internal/odf/odf_document.cpp b/src/odr/internal/odf/odf_document.cpp index e6139def..3554469f 100644 --- a/src/odr/internal/odf/odf_document.cpp +++ b/src/odr/internal/odf/odf_document.cpp @@ -1,11 +1,16 @@ #include +#include #include +#include #include #include +#include +#include #include #include +#include #include #include @@ -14,21 +19,40 @@ namespace odr::internal::odf { +namespace { +std::unique_ptr +create_element_adapter(const Document &document, ElementRegistry ®istry); +} + Document::Document(const FileType file_type, const DocumentType document_type, std::shared_ptr files) - : TemplateDocument(file_type, document_type, std::move(files)) { - m_content_xml = util::xml::parse(*m_filesystem, AbsPath("/content.xml")); + : internal::Document(file_type, document_type, std::move(files)) { + m_content_xml = util::xml::parse(*m_files, AbsPath("/content.xml")); - if (m_filesystem->exists(AbsPath("/styles.xml"))) { - m_styles_xml = util::xml::parse(*m_filesystem, AbsPath("/styles.xml")); + if (m_files->exists(AbsPath("/styles.xml"))) { + m_styles_xml = util::xml::parse(*m_files, AbsPath("/styles.xml")); } - m_root_element = parse_tree( - *this, - m_content_xml.document_element().child("office:body").first_child()); + // m_root_element = parse_tree( + // *this, + // m_content_xml.document_element().child("office:body").first_child()); m_style_registry = StyleRegistry(*this, m_content_xml.document_element(), m_styles_xml.document_element()); + + m_element_adapter = create_element_adapter(*this, m_element_registry); +} + +ElementRegistry &Document::element_registry() { return m_element_registry; } + +StyleRegistry &Document::style_registry() { return m_style_registry; } + +const ElementRegistry &Document::element_registry() const { + return m_element_registry; +} + +const StyleRegistry &Document::style_registry() const { + return m_style_registry; } bool Document::is_editable() const noexcept { return true; } @@ -42,12 +66,12 @@ void Document::save(const Path &path) const { zip::ZipArchive archive; // `mimetype` has to be the first file and uncompressed - if (m_filesystem->is_file(AbsPath("/mimetype"))) { + if (m_files->is_file(AbsPath("/mimetype"))) { archive.insert_file(std::end(archive), RelPath("mimetype"), - m_filesystem->open(AbsPath("/mimetype")), 0); + m_files->open(AbsPath("/mimetype")), 0); } - for (auto walker = m_filesystem->file_walker(AbsPath("/")); !walker->end(); + for (auto walker = m_files->file_walker(AbsPath("/")); !walker->end(); walker->next()) { const AbsPath &abs_path = walker->path(); RelPath rel_path = abs_path.rebase(AbsPath("/")); @@ -69,7 +93,7 @@ void Document::save(const Path &path) const { if (abs_path == Path("/META-INF/manifest.xml")) { // TODO auto manifest = - util::xml::parse(*m_filesystem, AbsPath("/META-INF/manifest.xml")); + util::xml::parse(*m_files, AbsPath("/META-INF/manifest.xml")); for (auto &&node : manifest.select_nodes("//manifest:encryption-data")) { node.node().parent().remove_child(node.node()); @@ -82,8 +106,7 @@ void Document::save(const Path &path) const { continue; } - archive.insert_file(std::end(archive), rel_path, - m_filesystem->open(abs_path)); + archive.insert_file(std::end(archive), rel_path, m_files->open(abs_path)); } std::ofstream ostream = util::file::create(path.string()); @@ -95,4 +118,855 @@ void Document::save(const Path & /*path*/, const char * /*password*/) const { throw UnsupportedOperation(); } +namespace { + +class ElementAdapter final : public abstract::ElementAdapter, + public abstract::TextRootAdapter, + public abstract::SlideAdapter, + public abstract::PageAdapter, + public abstract::SheetAdapter, + public abstract::SheetColumnAdapter, + public abstract::SheetRowAdapter, + public abstract::SheetCellAdapter, + public abstract::MasterPageAdapter, + public abstract::LineBreakAdapter, + public abstract::ParagraphAdapter, + public abstract::SpanAdapter, + public abstract::TextAdapter, + public abstract::LinkAdapter, + public abstract::BookmarkAdapter, + public abstract::ListItemAdapter, + public abstract::TableAdapter, + public abstract::TableColumnAdapter, + public abstract::TableRowAdapter, + public abstract::TableCellAdapter, + public abstract::FrameAdapter, + public abstract::RectAdapter, + public abstract::LineAdapter, + public abstract::CircleAdapter, + public abstract::CustomShapeAdapter, + public abstract::ImageAdapter { +public: + ElementAdapter(const Document &document, ElementRegistry ®istry) + : m_document(&document), m_registry(®istry) {} + + [[nodiscard]] ElementType + element_type(const ExtendedElementIdentifier element_id) const override { + return m_registry->element(element_id).type; + } + + [[nodiscard]] ExtendedElementIdentifier + element_parent(const ExtendedElementIdentifier element_id) const override { + return m_registry->element(element_id).parent_id; + } + [[nodiscard]] ExtendedElementIdentifier element_first_child( + const ExtendedElementIdentifier element_id) const override { + return ExtendedElementIdentifier( + m_registry->element(element_id).first_child_id); + } + [[nodiscard]] ExtendedElementIdentifier element_last_child( + const ExtendedElementIdentifier element_id) const override { + return ExtendedElementIdentifier( + m_registry->element(element_id).last_child_id); + } + [[nodiscard]] ExtendedElementIdentifier element_previous_sibling( + const ExtendedElementIdentifier element_id) const override { + return ExtendedElementIdentifier( + m_registry->element(element_id).previous_sibling_id); + } + [[nodiscard]] ExtendedElementIdentifier element_next_sibling( + const ExtendedElementIdentifier element_id) const override { + return ExtendedElementIdentifier( + m_registry->element(element_id).next_sibling_id); + } + + [[nodiscard]] bool element_is_editable( + const ExtendedElementIdentifier element_id) const override { + return m_registry->element(element_id).is_editable; + } + + [[nodiscard]] const TextRootAdapter * + text_root_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SlideAdapter * + slide_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const PageAdapter * + page_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SheetAdapter * + sheet_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SheetColumnAdapter * + sheet_column_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SheetRowAdapter * + sheet_row_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SheetCellAdapter * + sheet_cell_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const MasterPageAdapter * + master_page_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const LineBreakAdapter * + line_break_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const ParagraphAdapter * + paragraph_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const SpanAdapter * + span_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const TextAdapter * + text_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const LinkAdapter * + link_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const BookmarkAdapter * + bookmark_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const ListItemAdapter * + list_item_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const TableAdapter * + table_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const TableColumnAdapter * + table_column_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const TableRowAdapter * + table_row_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const TableCellAdapter * + table_cell_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const FrameAdapter * + frame_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const RectAdapter * + rect_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const LineAdapter * + line_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const CircleAdapter * + circle_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const CustomShapeAdapter * + custom_shape_adapter(const ExtendedElementIdentifier) const override { + return this; + } + [[nodiscard]] const ImageAdapter * + image_adapter(const ExtendedElementIdentifier) const override { + return this; + } + + [[nodiscard]] PageLayout text_root_page_layout( + const ExtendedElementIdentifier element_id) const override { + if (const ExtendedElementIdentifier master_page_id = + text_root_first_master_page(element_id); + !master_page_id.is_null()) { + return master_page_page_layout(master_page_id); + } + return {}; + } + [[nodiscard]] ExtendedElementIdentifier text_root_first_master_page( + const ExtendedElementIdentifier element_id) const override { + if (const ExtendedElementIdentifier first_master_page_id = + m_document->style_registry().first_master_page(); + !first_master_page_id.is_null()) { + return first_master_page_id; + } + return {}; + } + + [[nodiscard]] PageLayout + slide_page_layout(const ExtendedElementIdentifier element_id) const override { + if (const ExtendedElementIdentifier master_page_id = + slide_master_page(element_id); + !master_page_id.is_null()) { + return master_page_page_layout(master_page_id); + } + return {}; + } + [[nodiscard]] ExtendedElementIdentifier + slide_master_page(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute master_page_name_attr = + node.attribute("draw:master-page-name"); + master_page_name_attr) { + return m_document->style_registry().master_page( + master_page_name_attr.value()); + } + return {}; + } + [[nodiscard]] std::string + slide_name(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("draw:name").value(); + } + + [[nodiscard]] PageLayout + page_layout(const ExtendedElementIdentifier element_id) const override { + if (const ExtendedElementIdentifier master_page_id = + page_master_page(element_id); + !master_page_id.is_null()) { + return master_page_page_layout(master_page_id); + } + return {}; + } + [[nodiscard]] ExtendedElementIdentifier + page_master_page(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute master_page_name_attr = + node.attribute("draw:master-page-name"); + master_page_name_attr) { + return m_document->style_registry().master_page( + master_page_name_attr.value()); + } + return {}; + } + [[nodiscard]] std::string + page_name(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("draw:name").value(); + } + + [[nodiscard]] std::string + sheet_name(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("table:name").value(); + } + [[nodiscard]] TableDimensions + sheet_dimensions(const ExtendedElementIdentifier element_id) const override { + return {}; // TODO + } + [[nodiscard]] TableDimensions + sheet_content(const ExtendedElementIdentifier element_id, + const std::optional range) const override { + return {}; // TODO + } + [[nodiscard]] ExtendedElementIdentifier + sheet_column(const ExtendedElementIdentifier element_id, + const std::uint32_t column) const override { + return {}; // TODO + } + [[nodiscard]] ExtendedElementIdentifier + sheet_row(const ExtendedElementIdentifier element_id, + const std::uint32_t row) const override { + return {}; // TODO + } + [[nodiscard]] ExtendedElementIdentifier + sheet_cell(const ExtendedElementIdentifier element_id, + const std::uint32_t column, + const std::uint32_t row) const override { + return {}; // TODO + } + [[nodiscard]] ExtendedElementIdentifier + sheet_first_shape(const ExtendedElementIdentifier element_id) const override { + return {}; // TODO + } + [[nodiscard]] TableStyle + sheet_style(const ExtendedElementIdentifier element_id) const override { + return {}; // TODO + } + + [[nodiscard]] TableColumnStyle sheet_column_style( + const ExtendedElementIdentifier element_id) const override { + const ElementRegistry::Sheet &sheet_registry = + m_registry->sheet_element(element_id); + + if (const pugi::xml_node column_node = + sheet_registry.column(element_id.column()); + column_node) { + if (const pugi::xml_attribute attr = + column_node.attribute("table:style-name")) { + if (const Style *style = + m_document->style_registry().style(attr.value()); + style != nullptr) { + return style->resolved().table_column_style; + } + } + } + return {}; + } + + [[nodiscard]] TableRowStyle + sheet_row_style(const ExtendedElementIdentifier element_id) const override { + const ElementRegistry::Sheet &sheet_registry = + m_registry->sheet_element(element_id); + + if (const pugi::xml_node column_node = sheet_registry.row(element_id.row()); + column_node) { + if (const pugi::xml_attribute attr = + column_node.attribute("table:style-name")) { + if (const Style *style = + m_document->style_registry().style(attr.value()); + style != nullptr) { + return style->resolved().table_row_style; + } + } + } + return {}; + } + + [[nodiscard]] std::uint32_t + sheet_cell_column(const ExtendedElementIdentifier element_id) const override { + return element_id.column(); + } + [[nodiscard]] std::uint32_t + sheet_cell_row(const ExtendedElementIdentifier element_id) const override { + return element_id.row(); + } + [[nodiscard]] bool sheet_cell_is_covered( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return std::strcmp(node.name(), "table:covered-table-cell") == 0; + } + [[nodiscard]] TableDimensions + sheet_cell_span(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return {node.attribute("table:number-rows-spanned").as_uint(1), + node.attribute("table:number-columns-spanned").as_uint(1)}; + } + [[nodiscard]] ValueType sheet_cell_value_type( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const char *value_type = node.attribute("office:value-type").value(); + std::strcmp("float", value_type) == 0) { + return ValueType::float_number; + } + return ValueType::string; + } + [[nodiscard]] TableCellStyle + sheet_cell_style(const ExtendedElementIdentifier element_id) const override { + return get_partial_cell_style(element_id).table_cell_style; + } + + [[nodiscard]] PageLayout master_page_page_layout( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = + node.attribute("style:page-layout-name")) { + return m_document->style_registry().page_layout(attribute.value()); + } + return {}; + } + + [[nodiscard]] TextStyle + line_break_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).text_style; + } + + [[nodiscard]] ParagraphStyle + paragraph_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).paragraph_style; + } + [[nodiscard]] TextStyle paragraph_text_style( + const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).text_style; + } + + [[nodiscard]] TextStyle + span_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).text_style; + } + + [[nodiscard]] std::string + text_content(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node first = get_node(element_id); + const pugi::xml_node last = m_registry->text_element(element_id).last; + + std::string result; + for (pugi::xml_node node = first; node != last.next_sibling(); + node = node.next_sibling()) { + result += get_text(node); + } + return result; + } + void text_set_content(const ExtendedElementIdentifier element_id, + const std::string &text) const override { + const pugi::xml_node first = get_node(element_id); + const pugi::xml_node last = m_registry->text_element(element_id).last; + + pugi::xml_node parent = first.parent(); + const pugi::xml_node old_first = first; + const pugi::xml_node old_last = last; + pugi::xml_node new_first = old_first; + pugi::xml_node new_last = last; + + const auto insert_pcdata = [&] { + const pugi::xml_node new_node = parent.insert_child_before( + pugi::xml_node_type::node_pcdata, old_first); + if (new_first == old_first) { + new_first = new_node; + } + new_last = new_node; + return new_node; + }; + const auto insert_node = [&](const char *node) { + const pugi::xml_node new_node = + parent.insert_child_before(node, old_first); + if (new_first == old_first) { + new_first = new_node; + } + new_last = new_node; + return new_node; + }; + + for (const util::xml::StringToken &token : util::xml::tokenize_text(text)) { + switch (token.type) { + case util::xml::StringToken::Type::none: + break; + case util::xml::StringToken::Type::string: { + auto text_node = insert_pcdata(); + text_node.text().set(token.string.c_str()); + } break; + case util::xml::StringToken::Type::spaces: { + auto space_node = insert_node("text:s"); + space_node.prepend_attribute("text:c").set_value(token.string.size()); + } break; + case util::xml::StringToken::Type::tabs: { + for (std::size_t i = 0; i < token.string.size(); ++i) { + insert_node("text:tab"); + } + } break; + } + } + + m_registry->element(element_id).node = new_first; + m_registry->text_element(element_id).last = new_last; + + for (pugi::xml_node node = old_first; node != old_last.next_sibling();) { + const pugi::xml_node next = node.next_sibling(); + parent.remove_child(node); + node = next; + } + } + [[nodiscard]] TextStyle + text_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).text_style; + } + + [[nodiscard]] std::string + link_href(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("xlink:href").value(); + } + + [[nodiscard]] std::string + bookmark_name(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("text:name").value(); + } + + [[nodiscard]] TextStyle + list_item_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).text_style; + } + + [[nodiscard]] TableDimensions + table_dimensions(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + + TableDimensions result; + TableCursor cursor; + + for (auto column : node.children("table:table-column")) { + const auto columns_repeated = + column.attribute("table:number-columns-repeated").as_uint(1); + cursor.add_column(columns_repeated); + } + + result.columns = cursor.column(); + cursor = {}; + + for (auto row : node.children("table:table-row")) { + const auto rows_repeated = + row.attribute("table:number-rows-repeated").as_uint(1); + cursor.add_row(rows_repeated); + } + + result.rows = cursor.row(); + + return result; + } + [[nodiscard]] ExtendedElementIdentifier table_first_column( + const ExtendedElementIdentifier element_id) const override { + return ExtendedElementIdentifier( + m_registry->table_element(element_id).first_column_id); + } + [[nodiscard]] ExtendedElementIdentifier + table_first_row(const ExtendedElementIdentifier element_id) const override { + return element_first_child(element_id); + } + [[nodiscard]] TableStyle + table_style(const ExtendedElementIdentifier element_id) const override { + return get_partial_style(element_id).table_style; + } + + [[nodiscard]] TableColumnStyle table_column_style( + const ExtendedElementIdentifier element_id) const override { + return get_partial_style(element_id).table_column_style; + } + + [[nodiscard]] TableRowStyle + table_row_style(const ExtendedElementIdentifier element_id) const override { + return get_partial_style(element_id).table_row_style; + } + + [[nodiscard]] bool table_cell_is_covered( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return std::strcmp(node.name(), "table:covered-table-cell") == 0; + } + [[nodiscard]] TableDimensions + table_cell_span(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return {node.attribute("table:number-rows-spanned").as_uint(1), + node.attribute("table:number-columns-spanned").as_uint(1)}; + } + [[nodiscard]] ValueType table_cell_value_type( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const char *value_type = node.attribute("office:value-type").value(); + std::strcmp("float", value_type) == 0) { + return ValueType::float_number; + } + return ValueType::string; + } + [[nodiscard]] TableCellStyle + table_cell_style(const ExtendedElementIdentifier element_id) const override { + return get_partial_style(element_id).table_cell_style; + } + + [[nodiscard]] AnchorType + frame_anchor_type(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + + const char *anchor_type = node.attribute("text:anchor-type").value(); + if (std::strcmp("as-char", anchor_type) == 0) { + return AnchorType::as_char; + } + if (std::strcmp("char", anchor_type) == 0) { + return AnchorType::at_char; + } + if (std::strcmp("paragraph", anchor_type) == 0) { + return AnchorType::at_paragraph; + } + if (std::strcmp("page", anchor_type) == 0) { + return AnchorType::at_page; + } + return AnchorType::at_page; + } + [[nodiscard]] std::optional + frame_x(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:x")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::optional + frame_y(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:y")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::optional + frame_width(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:width")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::optional + frame_height(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:height")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::optional + frame_z_index(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:z-index")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] GraphicStyle + frame_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).graphic_style; + } + + [[nodiscard]] std::string + rect_x(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:x").value(); + } + [[nodiscard]] std::string + rect_y(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:y").value(); + } + [[nodiscard]] std::string + rect_width(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:width").value(); + } + [[nodiscard]] std::string + rect_height(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:height").value(); + } + [[nodiscard]] GraphicStyle + rect_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).graphic_style; + } + + [[nodiscard]] std::string + line_x1(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:x1").value(); + } + [[nodiscard]] std::string + line_y1(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:y1").value(); + } + [[nodiscard]] std::string + line_x2(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:x2").value(); + } + [[nodiscard]] std::string + line_y2(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:y2").value(); + } + [[nodiscard]] GraphicStyle + line_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).graphic_style; + } + + [[nodiscard]] std::string + circle_x(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:x").value(); + } + [[nodiscard]] std::string + circle_y(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:y").value(); + } + [[nodiscard]] std::string + circle_width(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:width").value(); + } + [[nodiscard]] std::string + circle_height(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:height").value(); + } + [[nodiscard]] GraphicStyle + circle_style(const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).graphic_style; + } + + [[nodiscard]] std::optional + custom_shape_x(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:x")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::optional + custom_shape_y(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + if (const pugi::xml_attribute attribute = node.attribute("svg:y")) { + return attribute.value(); + } + return std::nullopt; + } + [[nodiscard]] std::string custom_shape_width( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:width").value(); + } + [[nodiscard]] std::string custom_shape_height( + const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("svg:height").value(); + } + [[nodiscard]] GraphicStyle custom_shape_style( + const ExtendedElementIdentifier element_id) const override { + return get_intermediate_style(element_id).graphic_style; + } + + [[nodiscard]] bool + image_is_internal(const ExtendedElementIdentifier element_id) const override { + if (m_document->as_filesystem() == nullptr) { + return false; + } + try { + const AbsPath path = Path(image_href(element_id)).make_absolute(); + return m_document->as_filesystem()->is_file(path); + } catch (...) { + } + return false; + } + [[nodiscard]] std::optional + image_file(const ExtendedElementIdentifier element_id) const override { + if (m_document->as_filesystem() == nullptr) { + return std::nullopt; + } + const AbsPath path = Path(image_href(element_id)).make_absolute(); + return File(m_document->as_filesystem()->open(path)); + } + [[nodiscard]] std::string + image_href(const ExtendedElementIdentifier element_id) const override { + const pugi::xml_node node = get_node(element_id); + return node.attribute("xlink:href").value(); + } + +private: + const Document *m_document{nullptr}; + ElementRegistry *m_registry{nullptr}; + + [[nodiscard]] pugi::xml_node + get_node(const ExtendedElementIdentifier element_id) const { + return m_registry->element(element_id).node; + } + + [[nodiscard]] static std::string get_text(const pugi::xml_node node) { + if (node.type() == pugi::node_pcdata) { + return node.value(); + } + + const std::string name = node.name(); + if (name == "text:s") { + const std::size_t count = node.attribute("text:c").as_uint(1); + return std::string(count, ' '); + } + if (name == "text:tab") { + return "\t"; + } + return ""; + } + + [[nodiscard]] const char * + get_style_name(const ExtendedElementIdentifier element_id) const { + const pugi::xml_node node = get_node(element_id); + for (pugi::xml_attribute attribute : node.attributes()) { + if (util::string::ends_with(attribute.name(), ":style-name")) { + return attribute.value(); + } + } + return {}; + } + + [[nodiscard]] ResolvedStyle + get_partial_style(const ExtendedElementIdentifier element_id) const { + if (const ElementType type = element_type(element_id); + type == ElementType::sheet_cell) { + return get_partial_cell_style(element_id); + } + if (const char *style_name = get_style_name(element_id)) { + if (const Style *style = m_document->style_registry().style(style_name)) { + return style->resolved(); + } + } + return {}; + } + + [[nodiscard]] ResolvedStyle + get_intermediate_style(const ExtendedElementIdentifier element_id) const { + const ExtendedElementIdentifier parent_id = element_parent(element_id); + if (parent_id.is_null()) { + return get_partial_style(element_id); + } + ResolvedStyle base = get_intermediate_style(parent_id); + base.override(get_partial_style(element_id)); + return base; + } + + ResolvedStyle + get_partial_cell_style(const ExtendedElementIdentifier element_id) const { + const char *style_name = nullptr; + + const ElementRegistry::Sheet sheet_registry = + m_registry->sheet_element(element_id.without_extra()); + const auto [column, row] = element_id.cell(); + + const pugi::xml_node cell_node = sheet_registry.cell(column, row); + if (const pugi::xml_attribute attr = + cell_node.attribute("table:style-name")) { + style_name = attr.value(); + } + + if (style_name == nullptr) { + const pugi::xml_node row_node = sheet_registry.row(row); + if (const pugi::xml_attribute attr = + row_node.attribute("table:default-cell-style-name")) { + style_name = attr.value(); + } + } + if (style_name == nullptr) { + const pugi::xml_node column_node = sheet_registry.column(column); + if (const pugi::xml_attribute attr = + column_node.attribute("table:default-cell-style-name")) { + style_name = attr.value(); + } + } + + if (style_name != nullptr) { + if (const Style *style = m_document->style_registry().style(style_name); + style != nullptr) { + return style->resolved(); + } + } + + return {}; + } +}; + +std::unique_ptr +create_element_adapter(const Document &document, ElementRegistry ®istry) { + return std::make_unique(document, registry); +} + +} // namespace + } // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_document.hpp b/src/odr/internal/odf/odf_document.hpp index 37ac2041..90c1968c 100644 --- a/src/odr/internal/odf/odf_document.hpp +++ b/src/odr/internal/odf/odf_document.hpp @@ -3,10 +3,11 @@ #include #include -#include -#include +#include #include +#include + #include namespace odr::internal::abstract { @@ -15,24 +16,29 @@ class ReadableFilesystem; namespace odr::internal::odf { -class Document final : public TemplateDocument { +class Document final : public internal::Document { public: Document(FileType file_type, DocumentType document_type, std::shared_ptr files); + ElementRegistry &element_registry(); + StyleRegistry &style_registry(); + + const ElementRegistry &element_registry() const; + const StyleRegistry &style_registry() const; + [[nodiscard]] bool is_editable() const noexcept override; [[nodiscard]] bool is_savable(bool encrypted) const noexcept override; void save(const Path &path) const override; void save(const Path &path, const char *password) const override; -protected: +private: pugi::xml_document m_content_xml; pugi::xml_document m_styles_xml; + ElementRegistry m_element_registry; StyleRegistry m_style_registry; - - friend class Element; }; } // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_element.cpp b/src/odr/internal/odf/odf_element.cpp deleted file mode 100644 index 734a4a5c..00000000 --- a/src/odr/internal/odf/odf_element.cpp +++ /dev/null @@ -1,491 +0,0 @@ -#include - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace odr::internal::odf { - -namespace { - -const char *default_style_name(const pugi::xml_node node) { - for (pugi::xml_attribute attribute : node.attributes()) { - if (util::string::ends_with(attribute.name(), ":style-name")) { - return attribute.value(); - } - } - return {}; -} - -} // namespace - -Element::Element(const pugi::xml_node node) : m_node{node} { - if (!node) { - // TODO log error - throw std::runtime_error("node not set"); - } -} - -ResolvedStyle Element::partial_style(const abstract::Document *document) const { - if (const char *style_name = style_name_(document)) { - if (const Style *style = style_(document)->style(style_name)) { - return style->resolved(); - } - } - return {}; -} - -ResolvedStyle -Element::intermediate_style(const abstract::Document *document) const { - abstract::Element *parent = this->parent(document); - if (parent == nullptr) { - return partial_style(document); - } - ResolvedStyle base = - dynamic_cast(parent)->intermediate_style(document); - base.override(partial_style(document)); - return base; -} - -bool Element::is_editable(const abstract::Document *document) const { - if (m_parent == nullptr) { - return document_(document)->is_editable(); - } - return m_parent->is_editable(document); -} - -const char *Element::style_name_(const abstract::Document *) const { - return default_style_name(m_node); -} - -const Document *Element::document_(const abstract::Document *document) { - return dynamic_cast(document); -} - -const StyleRegistry *Element::style_(const abstract::Document *document) { - return &dynamic_cast(document)->m_style_registry; -} - -ElementType Root::type(const abstract::Document *) const { - return ElementType::root; -} - -ElementType TextRoot::type(const abstract::Document *) const { - return ElementType::root; -} - -PageLayout TextRoot::page_layout(const abstract::Document *document) const { - if (const auto *master_page = - dynamic_cast(this->first_master_page(document))) { - return master_page->page_layout(document); - } - return {}; -} - -abstract::Element * -TextRoot::first_master_page(const abstract::Document *document) const { - if (MasterPage *first_master_page = style_(document)->first_master_page()) { - return first_master_page; - } - return {}; -} - -PageLayout MasterPage::page_layout(const abstract::Document *document) const { - if (const pugi::xml_attribute attribute = - m_node.attribute("style:page-layout-name")) { - return style_(document)->page_layout(attribute.value()); - } - return {}; -} - -PageLayout Slide::page_layout(const abstract::Document *document) const { - if (const auto *master_page = - dynamic_cast(this->master_page(document))) { - return master_page->page_layout(document); - } - return {}; -} - -abstract::Element * -Slide::master_page(const abstract::Document *document) const { - if (const pugi::xml_attribute master_page_name_attr = - m_node.attribute("draw:master-page-name")) { - return style_(document)->master_page(master_page_name_attr.value()); - } - return {}; -} - -std::string Slide::name(const abstract::Document *) const { - return m_node.attribute("draw:name").value(); -} - -PageLayout Page::page_layout(const abstract::Document *document) const { - if (const auto *master_page = - dynamic_cast(this->master_page(document))) { - return master_page->page_layout(document); - } - return {}; -} - -abstract::Element *Page::master_page(const abstract::Document *document) const { - if (const pugi::xml_attribute master_page_name_attr = - m_node.attribute("draw:master-page-name")) { - return style_(document)->master_page(master_page_name_attr.value()); - } - return {}; -} - -std::string Page::name(const abstract::Document *) const { - return m_node.attribute("draw:name").value(); -} - -TextStyle LineBreak::style(const abstract::Document *document) const { - return intermediate_style(document).text_style; -} - -ParagraphStyle Paragraph::style(const abstract::Document *document) const { - return intermediate_style(document).paragraph_style; -} - -TextStyle Paragraph::text_style(const abstract::Document *document) const { - return intermediate_style(document).text_style; -} - -TextStyle Span::style(const abstract::Document *document) const { - return intermediate_style(document).text_style; -} - -Text::Text(const pugi::xml_node node) : Text(node, node) {} - -Text::Text(const pugi::xml_node first, const pugi::xml_node last) - : Element(first), m_last{last} { - if (!last) { - // TODO log error - throw std::runtime_error("last not set"); - } -} - -std::string Text::content(const abstract::Document *) const { - std::string result; - for (pugi::xml_node node = m_node; node != m_last.next_sibling(); - node = node.next_sibling()) { - result += text_(node); - } - return result; -} - -void Text::set_content(const abstract::Document *, const std::string &text) { - pugi::xml_node parent = m_node.parent(); - const pugi::xml_node old_first = m_node; - const pugi::xml_node old_last = m_last; - pugi::xml_node new_first = old_first; - pugi::xml_node new_last = m_last; - - const auto insert_pcdata = [&] { - const pugi::xml_node new_node = - parent.insert_child_before(pugi::xml_node_type::node_pcdata, old_first); - if (new_first == old_first) { - new_first = new_node; - } - new_last = new_node; - return new_node; - }; - const auto insert_node = [&](const char *node) { - const pugi::xml_node new_node = parent.insert_child_before(node, old_first); - if (new_first == old_first) { - new_first = new_node; - } - new_last = new_node; - return new_node; - }; - - for (const util::xml::StringToken &token : util::xml::tokenize_text(text)) { - switch (token.type) { - case util::xml::StringToken::Type::none: - break; - case util::xml::StringToken::Type::string: { - auto text_node = insert_pcdata(); - text_node.text().set(token.string.c_str()); - } break; - case util::xml::StringToken::Type::spaces: { - auto space_node = insert_node("text:s"); - space_node.prepend_attribute("text:c").set_value(token.string.size()); - } break; - case util::xml::StringToken::Type::tabs: { - for (std::size_t i = 0; i < token.string.size(); ++i) { - insert_node("text:tab"); - } - } break; - } - } - - m_node = new_first; - m_last = new_last; - - for (pugi::xml_node node = old_first; node != old_last.next_sibling();) { - const pugi::xml_node next = node.next_sibling(); - parent.remove_child(node); - node = next; - } -} - -TextStyle Text::style(const abstract::Document *document) const { - return intermediate_style(document).text_style; -} - -std::string Text::text_(const pugi::xml_node node) { - if (node.type() == pugi::node_pcdata) { - return node.value(); - } - - const std::string name = node.name(); - if (name == "text:s") { - const std::size_t count = node.attribute("text:c").as_uint(1); - return std::string(count, ' '); - } - if (name == "text:tab") { - return "\t"; - } - return ""; -} - -std::string Link::href(const abstract::Document *) const { - return m_node.attribute("xlink:href").value(); -} - -std::string Bookmark::name(const abstract::Document *) const { - return m_node.attribute("text:name").value(); -} - -TextStyle ListItem::style(const abstract::Document *document) const { - return intermediate_style(document).text_style; -} - -TableStyle Table::style(const abstract::Document *document) const { - return partial_style(document).table_style; -} - -TableDimensions Table::dimensions(const abstract::Document *) const { - TableDimensions result; - TableCursor cursor; - - for (auto column : m_node.children("table:table-column")) { - const auto columns_repeated = - column.attribute("table:number-columns-repeated").as_uint(1); - cursor.add_column(columns_repeated); - } - - result.columns = cursor.column(); - cursor = {}; - - for (auto row : m_node.children("table:table-row")) { - const auto rows_repeated = - row.attribute("table:number-rows-repeated").as_uint(1); - cursor.add_row(rows_repeated); - } - - result.rows = cursor.row(); - - return result; -} - -TableColumnStyle TableColumn::style(const abstract::Document *document) const { - return partial_style(document).table_column_style; -} - -TableRowStyle TableRow::style(const abstract::Document *document) const { - return partial_style(document).table_row_style; -} - -bool TableCell::is_covered(const abstract::Document *) const { - return std::strcmp(m_node.name(), "table:covered-table-cell") == 0; -} - -TableDimensions TableCell::span(const abstract::Document *) const { - return {m_node.attribute("table:number-rows-spanned").as_uint(1), - m_node.attribute("table:number-columns-spanned").as_uint(1)}; -} - -ValueType TableCell::value_type(const abstract::Document *) const { - if (const char *value_type = m_node.attribute("office:value-type").value(); - std::strcmp("float", value_type) == 0) { - return ValueType::float_number; - } - return ValueType::string; -} - -TableCellStyle TableCell::style(const abstract::Document *document) const { - return partial_style(document).table_cell_style; -} - -AnchorType Frame::anchor_type(const abstract::Document *) const { - const char *anchor_type = m_node.attribute("text:anchor-type").value(); - if (std::strcmp("as-char", anchor_type) == 0) { - return AnchorType::as_char; - } - if (std::strcmp("char", anchor_type) == 0) { - return AnchorType::at_char; - } - if (std::strcmp("paragraph", anchor_type) == 0) { - return AnchorType::at_paragraph; - } - if (std::strcmp("page", anchor_type) == 0) { - return AnchorType::at_page; - } - return AnchorType::at_page; -} - -std::optional Frame::x(const abstract::Document *) const { - if (const pugi::xml_attribute attribute = m_node.attribute("svg:x")) { - return attribute.value(); - } - return {}; -} - -std::optional Frame::y(const abstract::Document *) const { - if (const pugi::xml_attribute attribute = m_node.attribute("svg:y")) { - return attribute.value(); - } - return {}; -} - -std::optional Frame::width(const abstract::Document *) const { - if (const pugi::xml_attribute attribute = m_node.attribute("svg:width")) { - return attribute.value(); - } - return {}; -} - -std::optional Frame::height(const abstract::Document *) const { - if (const pugi::xml_attribute attribute = m_node.attribute("svg:height")) { - return attribute.value(); - } - return {}; -} - -std::optional Frame::z_index(const abstract::Document *) const { - if (const pugi::xml_attribute attribute = m_node.attribute("draw:z-index")) { - return attribute.value(); - } - return {}; -} - -GraphicStyle Frame::style(const abstract::Document *document) const { - return intermediate_style(document).graphic_style; -} - -std::string Rect::x(const abstract::Document *) const { - return m_node.attribute("svg:x").value(); -} - -std::string Rect::y(const abstract::Document *) const { - return m_node.attribute("svg:y").value(); -} - -std::string Rect::width(const abstract::Document *) const { - return m_node.attribute("svg:width").value(); -} - -std::string Rect::height(const abstract::Document *) const { - return m_node.attribute("svg:height").value(); -} - -GraphicStyle Rect::style(const abstract::Document *document) const { - return intermediate_style(document).graphic_style; -} - -std::string Line::x1(const abstract::Document *) const { - return m_node.attribute("svg:x1").value(); -} - -std::string Line::y1(const abstract::Document *) const { - return m_node.attribute("svg:y1").value(); -} - -std::string Line::x2(const abstract::Document *) const { - return m_node.attribute("svg:x2").value(); -} - -std::string Line::y2(const abstract::Document *) const { - return m_node.attribute("svg:y2").value(); -} - -GraphicStyle Line::style(const abstract::Document *document) const { - return intermediate_style(document).graphic_style; -} - -std::string Circle::x(const abstract::Document *) const { - return m_node.attribute("svg:x").value(); -} - -std::string Circle::y(const abstract::Document *) const { - return m_node.attribute("svg:y").value(); -} - -std::string Circle::width(const abstract::Document *) const { - return m_node.attribute("svg:width").value(); -} - -std::string Circle::height(const abstract::Document *) const { - return m_node.attribute("svg:height").value(); -} - -GraphicStyle Circle::style(const abstract::Document *document) const { - return intermediate_style(document).graphic_style; -} - -std::optional CustomShape::x(const abstract::Document *) const { - return m_node.attribute("svg:x").value(); -} - -std::optional CustomShape::y(const abstract::Document *) const { - return m_node.attribute("svg:y").value(); -} - -std::string CustomShape::width(const abstract::Document *) const { - return m_node.attribute("svg:width").value(); -} - -std::string CustomShape::height(const abstract::Document *) const { - return m_node.attribute("svg:height").value(); -} - -GraphicStyle CustomShape::style(const abstract::Document *document) const { - return intermediate_style(document).graphic_style; -} - -bool Image::is_internal(const abstract::Document *document) const { - const Document *doc = document_(document); - if (!doc || !doc->as_filesystem()) { - return false; - } - try { - const AbsPath path = Path(href(document)).make_absolute(); - return doc->as_filesystem()->is_file(path); - } catch (...) { - } - return false; -} - -std::optional Image::file(const abstract::Document *document) const { - const Document *doc = document_(document); - if (!doc || !is_internal(document)) { - return {}; - } - const AbsPath path = Path(href(document)).make_absolute(); - return File(doc->as_filesystem()->open(path)); -} - -std::string Image::href(const abstract::Document *) const { - return m_node.attribute("xlink:href").value(); -} - -} // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_element.hpp b/src/odr/internal/odf/odf_element.hpp deleted file mode 100644 index 26deff1e..00000000 --- a/src/odr/internal/odf/odf_element.hpp +++ /dev/null @@ -1,289 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -namespace odr::internal::odf { -class Document; -class StyleRegistry; - -class Element : public virtual internal::Element { -public: - explicit Element(pugi::xml_node); - - virtual ResolvedStyle partial_style(const abstract::Document *) const; - virtual ResolvedStyle intermediate_style(const abstract::Document *) const; - - bool is_editable(const abstract::Document *document) const override; - - pugi::xml_node m_node; - -protected: - virtual const char *style_name_(const abstract::Document *) const; - - static const Document *document_(const abstract::Document *); - static const StyleRegistry *style_(const abstract::Document *); -}; - -template -class DefaultElement final : public Element { -public: - explicit DefaultElement(const pugi::xml_node node) : Element(node) {} - - [[nodiscard]] ElementType type(const abstract::Document *) const override { - return element_type; - } -}; - -class Root : public Element { -public: - using Element::Element; - - [[nodiscard]] ElementType type(const abstract::Document *) const override; -}; - -class TextRoot final : public Root, public abstract::TextRoot { -public: - using Root::Root; - - [[nodiscard]] ElementType type(const abstract::Document *) const override; - - [[nodiscard]] PageLayout - page_layout(const abstract::Document *) const override; - - [[nodiscard]] abstract::Element * - first_master_page(const abstract::Document *) const override; -}; - -class PresentationRoot final : public Root { -public: - using Root::Root; -}; - -class DrawingRoot final : public Root { -public: - using Root::Root; -}; - -class MasterPage final : public Element, public abstract::MasterPage { -public: - using Element::Element; - - [[nodiscard]] PageLayout - page_layout(const abstract::Document *) const override; -}; - -class Slide final : public Element, public abstract::Slide { -public: - using Element::Element; - - [[nodiscard]] PageLayout - page_layout(const abstract::Document *) const override; - - [[nodiscard]] abstract::Element * - master_page(const abstract::Document *) const override; - - [[nodiscard]] std::string name(const abstract::Document *) const override; -}; - -class Page final : public Element, public abstract::Page { -public: - using Element::Element; - - [[nodiscard]] PageLayout - page_layout(const abstract::Document *) const override; - - [[nodiscard]] abstract::Element * - master_page(const abstract::Document *) const override; - - [[nodiscard]] std::string name(const abstract::Document *) const override; -}; - -class LineBreak final : public Element, public abstract::LineBreak { -public: - using Element::Element; - - [[nodiscard]] TextStyle style(const abstract::Document *) const override; -}; - -class Paragraph final : public Element, public abstract::Paragraph { -public: - using Element::Element; - - [[nodiscard]] ParagraphStyle style(const abstract::Document *) const override; - - [[nodiscard]] TextStyle text_style(const abstract::Document *) const override; -}; - -class Span final : public Element, public abstract::Span { -public: - using Element::Element; - - [[nodiscard]] TextStyle style(const abstract::Document *) const override; -}; - -class Text final : public Element, public abstract::Text { -public: - explicit Text(pugi::xml_node); - Text(pugi::xml_node first, pugi::xml_node last); - - [[nodiscard]] std::string content(const abstract::Document *) const override; - - void set_content(const abstract::Document *, - const std::string &text) override; - - [[nodiscard]] TextStyle style(const abstract::Document *) const override; - -private: - pugi::xml_node m_last; - - static std::string text_(pugi::xml_node); -}; - -class Link final : public Element, public abstract::Link { -public: - using Element::Element; - - [[nodiscard]] std::string href(const abstract::Document *) const override; -}; - -class Bookmark final : public Element, public abstract::Bookmark { -public: - using Element::Element; - - [[nodiscard]] std::string name(const abstract::Document *) const override; -}; - -class ListItem final : public Element, public abstract::ListItem { -public: - using Element::Element; - - [[nodiscard]] TextStyle style(const abstract::Document *) const override; -}; - -class Table final : public Element, public internal::Table { -public: - using Element::Element; - - [[nodiscard]] TableStyle style(const abstract::Document *) const override; - - [[nodiscard]] TableDimensions - dimensions(const abstract::Document *) const override; -}; - -class TableColumn final : public Element, public abstract::TableColumn { -public: - using Element::Element; - - [[nodiscard]] TableColumnStyle - style(const abstract::Document *) const override; -}; - -class TableRow final : public Element, public abstract::TableRow { -public: - using Element::Element; - - [[nodiscard]] TableRowStyle style(const abstract::Document *) const override; -}; - -class TableCell final : public Element, public abstract::TableCell { -public: - using Element::Element; - - [[nodiscard]] bool is_covered(const abstract::Document *) const override; - - [[nodiscard]] TableDimensions span(const abstract::Document *) const override; - - [[nodiscard]] ValueType value_type(const abstract::Document *) const override; - - [[nodiscard]] TableCellStyle style(const abstract::Document *) const override; -}; - -class Frame final : public Element, public abstract::Frame { -public: - using Element::Element; - - [[nodiscard]] AnchorType - anchor_type(const abstract::Document *) const override; - - [[nodiscard]] std::optional - x(const abstract::Document *) const override; - [[nodiscard]] std::optional - y(const abstract::Document *) const override; - [[nodiscard]] std::optional - width(const abstract::Document *) const override; - [[nodiscard]] std::optional - height(const abstract::Document *) const override; - - [[nodiscard]] std::optional - z_index(const abstract::Document *) const override; - - [[nodiscard]] GraphicStyle style(const abstract::Document *) const override; -}; - -class Rect final : public Element, public abstract::Rect { -public: - using Element::Element; - - [[nodiscard]] std::string x(const abstract::Document *) const override; - [[nodiscard]] std::string y(const abstract::Document *) const override; - [[nodiscard]] std::string width(const abstract::Document *) const override; - [[nodiscard]] std::string height(const abstract::Document *) const override; - - [[nodiscard]] GraphicStyle style(const abstract::Document *) const override; -}; - -class Line final : public Element, public abstract::Line { -public: - using Element::Element; - - [[nodiscard]] std::string x1(const abstract::Document *) const override; - [[nodiscard]] std::string y1(const abstract::Document *) const override; - [[nodiscard]] std::string x2(const abstract::Document *) const override; - [[nodiscard]] std::string y2(const abstract::Document *) const override; - - [[nodiscard]] GraphicStyle style(const abstract::Document *) const override; -}; - -class Circle final : public Element, public abstract::Circle { -public: - using Element::Element; - - [[nodiscard]] std::string x(const abstract::Document *) const override; - [[nodiscard]] std::string y(const abstract::Document *) const override; - [[nodiscard]] std::string width(const abstract::Document *) const override; - [[nodiscard]] std::string height(const abstract::Document *) const override; - - [[nodiscard]] GraphicStyle style(const abstract::Document *) const override; -}; - -class CustomShape final : public Element, public abstract::CustomShape { -public: - using Element::Element; - - [[nodiscard]] std::optional - x(const abstract::Document *) const override; - [[nodiscard]] std::optional - y(const abstract::Document *) const override; - [[nodiscard]] std::string width(const abstract::Document *) const override; - [[nodiscard]] std::string height(const abstract::Document *) const override; - - [[nodiscard]] GraphicStyle style(const abstract::Document *) const override; -}; - -class Image final : public Element, public abstract::Image { -public: - using Element::Element; - - [[nodiscard]] bool is_internal(const abstract::Document *) const override; - - [[nodiscard]] std::optional - file(const abstract::Document *) const override; - - [[nodiscard]] std::string href(const abstract::Document *) const override; -}; - -} // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_element_registry.cpp b/src/odr/internal/odf/odf_element_registry.cpp new file mode 100644 index 00000000..79ad347d --- /dev/null +++ b/src/odr/internal/odf/odf_element_registry.cpp @@ -0,0 +1,251 @@ +#include + +#include + +namespace odr::internal::odf { + +void ElementRegistry::clear() noexcept { m_elements.clear(); } + +[[nodiscard]] std::size_t ElementRegistry::size() const noexcept { + return m_elements.size(); +} + +ExtendedElementIdentifier ElementRegistry::create_element() { + m_elements.emplace_back(); + return ExtendedElementIdentifier(m_elements.size()); +} + +ElementRegistry::Table & +ElementRegistry::create_table_element(ExtendedElementIdentifier id) { + check_element_id(id); + auto [it, success] = m_tables.emplace(id.element_id(), Table{}); + return it->second; +} + +ElementRegistry::Text & +ElementRegistry::create_text_element(ExtendedElementIdentifier id) { + check_element_id(id); + auto [it, success] = m_texts.emplace(id.element_id(), Text{}); + return it->second; +} + +ElementRegistry::Sheet & +ElementRegistry::create_sheet_element(ExtendedElementIdentifier id) { + check_element_id(id); + auto [it, success] = m_sheets.emplace(id.element_id(), Sheet{}); + return it->second; +} + +[[nodiscard]] ElementRegistry::Element & +ElementRegistry::element(const ExtendedElementIdentifier id) { + check_element_id(id); + return m_elements.at(id.element_id() - 1); +} + +[[nodiscard]] const ElementRegistry::Element & +ElementRegistry::element(const ExtendedElementIdentifier id) const { + check_element_id(id); + return m_elements.at(id.element_id() - 1); +} + +[[nodiscard]] ElementRegistry::Table & +ElementRegistry::table_element(const ExtendedElementIdentifier id) { + check_table_id(id); + return m_tables.at(id.element_id()); +} + +[[nodiscard]] const ElementRegistry::Table & +ElementRegistry::table_element(const ExtendedElementIdentifier id) const { + check_table_id(id); + return m_tables.at(id.element_id()); +} + +[[nodiscard]] ElementRegistry::Text & +ElementRegistry::text_element(const ExtendedElementIdentifier id) { + check_text_id(id); + return m_texts.at(id.element_id()); +} + +[[nodiscard]] const ElementRegistry::Text & +ElementRegistry::text_element(const ExtendedElementIdentifier id) const { + check_text_id(id); + return m_texts.at(id.element_id()); +} + +[[nodiscard]] ElementRegistry::Sheet & +ElementRegistry::sheet_element(const ExtendedElementIdentifier id) { + check_element_id(id); + if (!m_sheets.contains(id.element_id())) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier not found"); + } + return m_sheets.at(id.element_id()); +} + +[[nodiscard]] const ElementRegistry::Sheet & +ElementRegistry::sheet_element(const ExtendedElementIdentifier id) const { + check_element_id(id); + if (!m_sheets.contains(id.element_id())) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier not found"); + } + return m_sheets.at(id.element_id()); +} + +void ElementRegistry::append_child(const ExtendedElementIdentifier parent_id, + const ExtendedElementIdentifier child_id) { + check_element_id(parent_id); + check_element_id(child_id); + + const ExtendedElementIdentifier previous_sibling_id( + element(parent_id).last_child_id); + + element(child_id).parent_id = parent_id; + element(child_id).first_child_id = null_element_id; + element(child_id).last_child_id = null_element_id; + element(child_id).previous_sibling_id = previous_sibling_id.element_id(); + element(child_id).next_sibling_id = null_element_id; + + if (element(parent_id).first_child_id == null_element_id) { + element(parent_id).first_child_id = child_id.element_id(); + } else { + element(previous_sibling_id).next_sibling_id = child_id.element_id(); + } + element(parent_id).last_child_id = child_id.element_id(); +} + +void ElementRegistry::append_column(const ExtendedElementIdentifier table_id, + const ExtendedElementIdentifier column_id) { + check_table_id(table_id); + check_element_id(column_id); + + const ExtendedElementIdentifier previous_sibling_id( + table_element(table_id).last_column_id); + + element(column_id).parent_id = table_id; + element(column_id).first_child_id = null_element_id; + element(column_id).last_child_id = null_element_id; + element(column_id).previous_sibling_id = previous_sibling_id.element_id(); + element(column_id).next_sibling_id = null_element_id; + + if (table_element(table_id).first_column_id == null_element_id) { + table_element(table_id).first_column_id = column_id.element_id(); + } else { + element(previous_sibling_id).next_sibling_id = column_id.element_id(); + } + table_element(table_id).last_column_id = column_id.element_id(); +} + +void ElementRegistry::append_shape(const ExtendedElementIdentifier sheet_id, + const ExtendedElementIdentifier shape_id) { + check_sheet_id(sheet_id); + check_element_id(shape_id); + + const ExtendedElementIdentifier previous_sibling_id( + sheet_element(sheet_id).last_shape_id); + + element(shape_id).parent_id = sheet_id; + element(shape_id).first_child_id = null_element_id; + element(shape_id).last_child_id = null_element_id; + element(shape_id).previous_sibling_id = previous_sibling_id.element_id(); + element(shape_id).next_sibling_id = null_element_id; + + if (sheet_element(sheet_id).first_shape_id == null_element_id) { + sheet_element(sheet_id).first_shape_id = shape_id.element_id(); + } else { + element(previous_sibling_id).next_sibling_id = shape_id.element_id(); + } + sheet_element(sheet_id).last_shape_id = shape_id.element_id(); +} + +void ElementRegistry::check_element_id( + const ExtendedElementIdentifier id) const { + if (id.is_null()) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: null identifier"); + } + if (id.element_id() - 1 >= m_elements.size()) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier out of range"); + } +} + +void ElementRegistry::check_table_id(const ExtendedElementIdentifier id) const { + check_element_id(id); + if (!m_tables.contains(id.element_id())) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier not found"); + } +} + +void ElementRegistry::check_text_id(const ExtendedElementIdentifier id) const { + check_element_id(id); + if (!m_texts.contains(id.element_id())) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier not found"); + } +} + +void ElementRegistry::check_sheet_id(const ExtendedElementIdentifier id) const { + check_element_id(id); + if (!m_sheets.contains(id.element_id())) { + throw std::out_of_range( + "DocumentElementRegistry::check_id: identifier not found"); + } +} + +void ElementRegistry::Sheet::create_column(const std::uint32_t column, + const std::uint32_t repeated, + const pugi::xml_node element) { + columns[column + repeated] = {.node = element}; +} + +void ElementRegistry::Sheet::create_row(const std::uint32_t row, + const std::uint32_t repeated, + const pugi::xml_node element) { + rows[row + repeated].node = element; +} + +void ElementRegistry::Sheet::create_cell(const std::uint32_t column, + const std::uint32_t row, + const std::uint32_t columns_repeated, + const std::uint32_t rows_repeated, + const pugi::xml_node element) { + const bool is_repeated = columns_repeated > 1 || rows_repeated > 1; + + Cell &cell = rows[row + rows_repeated].cells[column + columns_repeated]; + cell.node = element; + cell.is_repeated = is_repeated; +} + +pugi::xml_node +ElementRegistry::Sheet::column(const std::uint32_t column) const { + if (const auto it = util::map::lookup_greater_than(columns, column); + it != std::end(columns)) { + return it->second.node; + } + return {}; +} + +pugi::xml_node ElementRegistry::Sheet::row(const std::uint32_t row) const { + if (const auto it = util::map::lookup_greater_than(rows, row); + it != std::end(rows)) { + return it->second.node; + } + return {}; +} + +pugi::xml_node ElementRegistry::Sheet::cell(const std::uint32_t column, + const std::uint32_t row) const { + if (const auto row_it = util::map::lookup_greater_than(rows, row); + row_it != std::end(rows)) { + const auto &cells = row_it->second.cells; + if (const auto cell_it = util::map::lookup_greater_than(cells, column); + cell_it != std::end(cells)) { + return cell_it->second.node; + } + } + return {}; +} + +} // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_element_registry.hpp b/src/odr/internal/odf/odf_element_registry.hpp new file mode 100644 index 00000000..a3ae7372 --- /dev/null +++ b/src/odr/internal/odf/odf_element_registry.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +#include + +namespace odr::internal::odf { + +class ElementRegistry final { +public: + struct Element final { + ExtendedElementIdentifier parent_id; + ElementIdentifier first_child_id{null_element_id}; + ElementIdentifier last_child_id{null_element_id}; + ElementIdentifier previous_sibling_id{null_element_id}; + ElementIdentifier next_sibling_id{null_element_id}; + ElementType type{ElementType::none}; + pugi::xml_node node; + bool is_editable{false}; + }; + + struct Table final { + ElementIdentifier first_column_id{null_element_id}; + ElementIdentifier last_column_id{null_element_id}; + }; + + struct Text final { + pugi::xml_node last; + }; + + struct Sheet final { + struct Column final { + pugi::xml_node node; + }; + + struct Cell final { + pugi::xml_node node; + bool is_repeated{false}; + }; + + struct Row final { + pugi::xml_node node; + std::map cells; + }; + + TableDimensions dimensions; + + std::map columns; + std::map rows; + + ElementIdentifier first_shape_id{null_element_id}; + ElementIdentifier last_shape_id{null_element_id}; + + void create_column(std::uint32_t column, std::uint32_t repeated, + pugi::xml_node element); + void create_row(std::uint32_t row, std::uint32_t repeated, + pugi::xml_node element); + void create_cell(std::uint32_t column, std::uint32_t row, + std::uint32_t columns_repeated, + std::uint32_t rows_repeated, pugi::xml_node element); + + [[nodiscard]] pugi::xml_node column(std::uint32_t) const; + [[nodiscard]] pugi::xml_node row(std::uint32_t) const; + [[nodiscard]] pugi::xml_node cell(std::uint32_t column, + std::uint32_t row) const; + }; + + void clear() noexcept; + + [[nodiscard]] std::size_t size() const noexcept; + + ExtendedElementIdentifier create_element(); + Table &create_table_element(ExtendedElementIdentifier id); + Text &create_text_element(ExtendedElementIdentifier id); + Sheet &create_sheet_element(ExtendedElementIdentifier id); + + [[nodiscard]] Element &element(ExtendedElementIdentifier id); + [[nodiscard]] const Element &element(ExtendedElementIdentifier id) const; + + [[nodiscard]] Table &table_element(ExtendedElementIdentifier id); + [[nodiscard]] const Table &table_element(ExtendedElementIdentifier id) const; + + [[nodiscard]] Text &text_element(ExtendedElementIdentifier id); + [[nodiscard]] const Text &text_element(ExtendedElementIdentifier id) const; + + [[nodiscard]] Sheet &sheet_element(ExtendedElementIdentifier id); + [[nodiscard]] const Sheet &sheet_element(ExtendedElementIdentifier id) const; + + void append_child(ExtendedElementIdentifier parent_id, + ExtendedElementIdentifier child_id); + void append_column(ExtendedElementIdentifier table_id, + ExtendedElementIdentifier column_id); + void append_shape(ExtendedElementIdentifier sheet_id, + ExtendedElementIdentifier shape_id); + +private: + std::vector m_elements; + std::unordered_map m_tables; + std::unordered_map m_texts; + std::unordered_map m_sheets; + + void check_element_id(ExtendedElementIdentifier id) const; + void check_table_id(ExtendedElementIdentifier id) const; + void check_text_id(ExtendedElementIdentifier id) const; + void check_sheet_id(ExtendedElementIdentifier id) const; +}; + +} // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_parser.cpp b/src/odr/internal/odf/odf_parser.cpp index bbffb659..95fe569c 100644 --- a/src/odr/internal/odf/odf_parser.cpp +++ b/src/odr/internal/odf/odf_parser.cpp @@ -1,14 +1,58 @@ #include -#include -#include +#include +#include #include +#include + namespace odr::internal::odf { namespace { +using TreeParser = + std::function( + ElementRegistry ®istry, pugi::xml_node node)>; +using ChildrenParser = std::function; + +std::tuple +parse_any_element_tree(ElementRegistry ®istry, pugi::xml_node node); + +void parse_any_element_children(ElementRegistry ®istry, + const ExtendedElementIdentifier parent_id, + const pugi::xml_node node) { + for (pugi::xml_node child_node = node.first_child(); child_node;) { + if (auto [child_id, next_sibling] = + parse_any_element_tree(registry, child_node); + child_id.is_null()) { + child_node = child_node.next_sibling(); + } else { + registry.append_child(parent_id, child_id); + child_node = next_sibling; + } + } +} + +std::tuple +parse_element_tree(ElementRegistry ®istry, const ElementType type, + const pugi::xml_node node, + const ChildrenParser &children_parser) { + if (!node) { + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; + } + + const ExtendedElementIdentifier element_id = registry.create_element(); + ElementRegistry::Element &element = registry.element(element_id); + element.type = type; + + children_parser(registry, element_id, node); + + return {element_id, node.next_sibling()}; +} + bool is_text_node(const pugi::xml_node node) { if (!node) { return false; @@ -29,188 +73,263 @@ bool is_text_node(const pugi::xml_node node) { return false; } -} // namespace - -} // namespace odr::internal::odf - -namespace odr::internal { - -odf::Element *odf::parse_tree(Document &document, const pugi::xml_node node) { - auto [root, _] = parse_any_element_tree(document, node); - return root; -} - -void odf::parse_element_children(Document &document, Element *element, - const pugi::xml_node node) { - for (auto child_node = node.first_child(); child_node;) { - if (auto [child, next_sibling] = - parse_any_element_tree(document, child_node); - child == nullptr) { - child_node = child_node.next_sibling(); - } else { - element->append_child_(child); - child_node = next_sibling; - } +std::tuple +parse_text_element(ElementRegistry ®istry, const pugi::xml_node first) { + if (!first) { + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; } -} -void odf::parse_element_children(Document &document, PresentationRoot *element, - const pugi::xml_node node) { - for (const pugi::xml_node child_node : node.children("draw:page")) { - auto [child, _] = parse_element_tree(document, child_node); - element->append_child_(child); - } -} + const ExtendedElementIdentifier element_id = registry.create_element(); + auto &[last] = registry.create_text_element(element_id); -void odf::parse_element_children(Document &document, SpreadsheetRoot *element, - const pugi::xml_node node) { - for (const pugi::xml_node child_node : node.children("table:table")) { - auto [child, _] = parse_element_tree(document, child_node); - element->append_child_(child); + for (last = first; is_text_node(last.next_sibling()); + last = last.next_sibling()) { } -} -void odf::parse_element_children(Document &document, DrawingRoot *element, - const pugi::xml_node node) { - for (const pugi::xml_node child_node : node.children("draw:page")) { - auto [child, _] = parse_element_tree(document, child_node); - element->append_child_(child); - } + return {element_id, last.next_sibling()}; } -template <> -std::tuple -odf::parse_element_tree(Document &document, pugi::xml_node node) { +std::tuple +parse_table_row(ElementRegistry ®istry, const pugi::xml_node node) { if (!node) { - return std::make_tuple(nullptr, pugi::xml_node()); + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; } - pugi::xml_node last = node; - for (; is_text_node(last.next_sibling()); last = last.next_sibling()) { - } + const ExtendedElementIdentifier element_id = registry.create_element(); - auto element_unique = std::make_unique(node, last); - auto element = element_unique.get(); - document.register_element_(std::move(element_unique)); + for (const pugi::xml_node cell_node : node.children()) { + // TODO log warning if repeated + auto [cell, _] = parse_any_element_tree(registry, cell_node); + registry.append_child(element_id, cell); + } - return std::make_tuple(element, last.next_sibling()); + return {element_id, node.next_sibling()}; } -template <> -std::tuple -odf::parse_element_tree(Document &document, pugi::xml_node node) { +std::tuple +parse_table(ElementRegistry ®istry, const pugi::xml_node node) { if (!node) { - return std::make_tuple(nullptr, pugi::xml_node()); + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; } - auto table_unique = std::make_unique(node); - auto table = table_unique.get(); - document.register_element_(std::move(table_unique)); + const ExtendedElementIdentifier element_id = registry.create_element(); // TODO inflate table first? - for (auto column_node : node.children("table:table-column")) { - for (std::uint32_t i = 0; - i < column_node.attribute("table:number-columns-repeated").as_uint(1); - ++i) { + for (const pugi::xml_node column_node : node.children("table:table-column")) { + const std::uint32_t repeat = + column_node.attribute("table:number-columns-repeated").as_uint(1); + for (std::uint32_t i = 0; i < repeat; ++i) { // TODO mark as repeated - auto [column, _] = parse_element_tree(document, column_node); - table->append_column_(column); + auto [column_id, _] = parse_any_element_tree(registry, column_node); + registry.append_column(element_id, column_id); } } for (const pugi::xml_node row_node : node.children("table:table-row")) { // TODO log warning if repeated - auto [row, _] = parse_element_tree(document, row_node); - table->append_row_(row); + auto [row_id, _] = parse_any_element_tree(registry, row_node); + registry.append_child(element_id, row_id); } - return std::make_tuple(table, node.next_sibling()); + return {element_id, node.next_sibling()}; } -template <> -std::tuple -odf::parse_element_tree(Document &document, - const pugi::xml_node node) { +std::tuple +parse_sheet(ElementRegistry ®istry, const pugi::xml_node node) { if (!node) { - return std::make_tuple(nullptr, pugi::xml_node()); + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; } - auto table_row_unique = std::make_unique(node); - auto table_row = table_row_unique.get(); - document.register_element_(std::move(table_row_unique)); + const ExtendedElementIdentifier element_id = registry.create_element(); + ElementRegistry::Sheet &sheet = registry.create_sheet_element(element_id); - for (const pugi::xml_node cell_node : node.children()) { - // TODO log warning if repeated - auto [cell, _] = parse_any_element_tree(document, cell_node); - table_row->append_child_(cell); + TableCursor cursor; + + for (const pugi::xml_node column_node : node.children("table:table-column")) { + const std::uint32_t columns_repeated = + column_node.attribute("table:number-columns-repeated").as_uint(1); + + sheet.create_column(cursor.column(), columns_repeated, column_node); + + cursor.add_column(columns_repeated); + } + + sheet.dimensions.columns = cursor.column(); + cursor = {}; + + for (const pugi::xml_node row_node : node.children("table:table-row")) { + const std::uint32_t rows_repeated = + row_node.attribute("table:number-rows-repeated").as_uint(1); + + sheet.create_row(cursor.row(), rows_repeated, row_node); + + // TODO covered cells + for (const pugi::xml_node cell_node : + row_node.children("table:table-cell")) { + const std::uint32_t columns_repeated = + cell_node.attribute("table:number-columns-repeated").as_uint(1); + const std::uint32_t colspan = + cell_node.attribute("table:number-columns-spanned").as_uint(1); + const std::uint32_t rowspan = + cell_node.attribute("table:number-rows-spanned").as_uint(1); + + sheet.create_cell(cursor.column(), cursor.row(), columns_repeated, + rows_repeated, cell_node); + + bool empty = false; + if (!cell_node.first_child()) { + empty = true; + } + + if (!empty) { + for (std::uint32_t row_repeat = 0; row_repeat < rows_repeated; + ++row_repeat) { + for (std::uint32_t column_repeat = 0; + column_repeat < columns_repeated; ++column_repeat) { + const ExtendedElementIdentifier cell_id = + ExtendedElementIdentifier::make_cell( + element_id.element_id(), cursor.column() + column_repeat, + cursor.row() + row_repeat); + parse_any_element_children(registry, cell_id, cell_node); + } + } + } + + cursor.add_cell(colspan, rowspan, columns_repeated); + } + + cursor.add_row(rows_repeated); + } + + sheet.dimensions.rows = cursor.row(); + + for (const pugi::xml_node shape_node : + node.child("table:shapes").children()) { + if (auto [shape_id, _] = parse_any_element_tree(registry, shape_node); + !shape_id.is_null()) { + registry.append_shape(element_id, shape_id); + } + } + + return {element_id, node.next_sibling()}; +} + +void parse_presentation_children(ElementRegistry ®istry, + const ExtendedElementIdentifier root_id, + const pugi::xml_node node) { + for (const pugi::xml_node child_node : node.children("draw:page")) { + auto [child_id, _] = parse_any_element_tree(registry, child_node); + registry.append_child(root_id, child_id); + } +} + +void parse_spreadsheet_children(ElementRegistry ®istry, + const ExtendedElementIdentifier root_id, + const pugi::xml_node node) { + for (const pugi::xml_node child_node : node.children("table:table")) { + auto [child_id, _] = parse_sheet(registry, child_node); + registry.append_child(root_id, child_id); } +} - return std::make_tuple(table_row, node.next_sibling()); +void parse_drawing_children(ElementRegistry ®istry, + const ExtendedElementIdentifier root_id, + const pugi::xml_node node) { + for (const pugi::xml_node child_node : node.children("draw:page")) { + auto [child_id, _] = parse_any_element_tree(registry, child_node); + registry.append_child(root_id, child_id); + } } -std::tuple -odf::parse_any_element_tree(Document &document, const pugi::xml_node node) { - using Parser = std::function( - Document & document, pugi::xml_node node)>; - - using List = DefaultElement; - using Group = DefaultElement; - using PageBreak = DefaultElement; - - static std::unordered_map parser_table{ - {"office:text", parse_element_tree}, - {"office:presentation", parse_element_tree}, - {"office:spreadsheet", parse_element_tree}, - {"office:drawing", parse_element_tree}, - {"text:p", parse_element_tree}, - {"text:h", parse_element_tree}, - {"text:span", parse_element_tree}, - {"text:s", parse_element_tree}, - {"text:tab", parse_element_tree}, - {"text:line-break", parse_element_tree}, - {"text:a", parse_element_tree}, - {"text:bookmark", parse_element_tree}, - {"text:bookmark-start", parse_element_tree}, - {"text:list", parse_element_tree}, - {"text:list-header", parse_element_tree}, - {"text:list-item", parse_element_tree}, - {"text:index-title", parse_element_tree}, - {"text:table-of-content", parse_element_tree}, - {"text:illustration-index", parse_element_tree}, - {"text:index-body", parse_element_tree}, - {"text:soft-page-break", parse_element_tree}, - {"text:date", parse_element_tree}, - {"text:time", parse_element_tree}, - {"text:section", parse_element_tree}, - //{"text:page-number", parse_element_tree}, - //{"text:page-continuation", parse_element_tree}, - {"table:table", parse_element_tree
}, - {"table:table-column", parse_element_tree}, - {"table:table-row", parse_element_tree}, - {"table:table-cell", parse_element_tree}, - {"table:covered-table-cell", parse_element_tree}, - {"draw:frame", parse_element_tree}, - {"draw:image", parse_element_tree}, - {"draw:rect", parse_element_tree}, - {"draw:line", parse_element_tree}, - {"draw:circle", parse_element_tree}, - {"draw:custom-shape", parse_element_tree}, - {"draw:text-box", parse_element_tree}, - {"draw:g", parse_element_tree}, - {"draw:a", parse_element_tree}, - {"style:master-page", parse_element_tree}}; +std::tuple +parse_any_element_tree(ElementRegistry ®istry, const pugi::xml_node node) { + const auto create_default_tree_parser = + [](const ElementType type, + const ChildrenParser &children_parser = parse_any_element_children) { + return [type, children_parser](ElementRegistry &r, + const pugi::xml_node n) { + return parse_element_tree(r, type, n, children_parser); + }; + }; + + static std::unordered_map parser_table{ + {"office:text", create_default_tree_parser(ElementType::root)}, + {"office:presentation", + create_default_tree_parser(ElementType::root, + parse_presentation_children)}, + {"office:spreadsheet", + create_default_tree_parser(ElementType::root, + parse_spreadsheet_children)}, + {"office:drawing", + create_default_tree_parser(ElementType::root, parse_drawing_children)}, + {"text:p", create_default_tree_parser(ElementType::paragraph)}, + {"text:h", create_default_tree_parser(ElementType::paragraph)}, + {"text:span", create_default_tree_parser(ElementType::span)}, + {"text:s", create_default_tree_parser(ElementType::text)}, + {"text:tab", create_default_tree_parser(ElementType::text)}, + {"text:line-break", create_default_tree_parser(ElementType::line_break)}, + {"text:a", create_default_tree_parser(ElementType::link)}, + {"text:bookmark", create_default_tree_parser(ElementType::bookmark)}, + {"text:bookmark-start", + create_default_tree_parser(ElementType::bookmark)}, + {"text:list", create_default_tree_parser(ElementType::list)}, + {"text:list-header", create_default_tree_parser(ElementType::list_item)}, + {"text:list-item", create_default_tree_parser(ElementType::list_item)}, + {"text:index-title", create_default_tree_parser(ElementType::group)}, + {"text:table-of-content", create_default_tree_parser(ElementType::group)}, + {"text:illustration-index", + create_default_tree_parser(ElementType::group)}, + {"text:index-body", create_default_tree_parser(ElementType::group)}, + {"text:soft-page-break", + create_default_tree_parser(ElementType::page_break)}, + {"text:date", create_default_tree_parser(ElementType::group)}, + {"text:time", create_default_tree_parser(ElementType::group)}, + {"text:section", create_default_tree_parser(ElementType::group)}, + //{"text:page-number", create_tree_parser(ElementType::group)}, + //{"text:page-continuation", create_tree_parser(ElementType::group)}, + {"table:table", parse_table}, + {"table:table-column", + create_default_tree_parser(ElementType::table_column)}, + {"table:table-row", parse_table_row}, + {"table:table-cell", create_default_tree_parser(ElementType::table_cell)}, + {"table:covered-table-cell", + create_default_tree_parser(ElementType::table_cell)}, + {"draw:frame", create_default_tree_parser(ElementType::frame)}, + {"draw:image", create_default_tree_parser(ElementType::image)}, + {"draw:rect", create_default_tree_parser(ElementType::rect)}, + {"draw:line", create_default_tree_parser(ElementType::line)}, + {"draw:circle", create_default_tree_parser(ElementType::circle)}, + {"draw:custom-shape", + create_default_tree_parser(ElementType::custom_shape)}, + {"draw:text-box", create_default_tree_parser(ElementType::group)}, + {"draw:g", create_default_tree_parser(ElementType::frame)}, + {"draw:a", create_default_tree_parser(ElementType::link)}, + {"style:master-page", + create_default_tree_parser(ElementType::master_page)}}; if (node.type() == pugi::xml_node_type::node_pcdata) { - return parse_element_tree(document, node); + return parse_text_element(registry, node); } if (const auto constructor_it = parser_table.find(node.name()); constructor_it != std::end(parser_table)) { - return constructor_it->second(document, node); + return constructor_it->second(registry, node); } - return std::make_tuple(nullptr, pugi::xml_node()); + return {ExtendedElementIdentifier::null(), pugi::xml_node()}; +} + +} // namespace + +} // namespace odr::internal::odf + +namespace odr::internal { + +ExtendedElementIdentifier odf::parse_tree(ElementRegistry ®istry, + const pugi::xml_node node) { + auto [root, _] = parse_any_element_tree(registry, node); + return root; } } // namespace odr::internal diff --git a/src/odr/internal/odf/odf_parser.hpp b/src/odr/internal/odf/odf_parser.hpp index cb3aef78..5eab1c54 100644 --- a/src/odr/internal/odf/odf_parser.hpp +++ b/src/odr/internal/odf/odf_parser.hpp @@ -1,58 +1,15 @@ #pragma once -#include +#include -#include -#include -#include +namespace pugi { +class xml_node; +} // namespace pugi namespace odr::internal::odf { -class Element; -class PresentationRoot; -class SpreadsheetRoot; -class DrawingRoot; -class Text; -class Table; -class TableRow; +class ElementRegistry; -Element *parse_tree(Document &document, pugi::xml_node node); - -template -std::tuple -parse_element_tree(Document &document, pugi::xml_node node, args_t &&...args) { - if (!node) { - return std::make_tuple(nullptr, pugi::xml_node()); - } - - auto element_unique = - std::make_unique(node, std::forward(args)...); - auto element = element_unique.get(); - document.register_element_(std::move(element_unique)); - - parse_element_children(document, element, node); - - return std::make_tuple(element, node.next_sibling()); -} -template <> -std::tuple -parse_element_tree(Document &document, pugi::xml_node node); -template <> -std::tuple
-parse_element_tree
(Document &document, pugi::xml_node node); -template <> -std::tuple -parse_element_tree(Document &document, pugi::xml_node node); - -std::tuple -parse_any_element_tree(Document &document, pugi::xml_node node); - -void parse_element_children(Document &document, Element *element, - pugi::xml_node node); -void parse_element_children(Document &document, PresentationRoot *element, - pugi::xml_node node); -void parse_element_children(Document &document, SpreadsheetRoot *element, - pugi::xml_node node); -void parse_element_children(Document &document, DrawingRoot *element, - pugi::xml_node node); +ExtendedElementIdentifier parse_tree(ElementRegistry ®istry, + pugi::xml_node node); } // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_spreadsheet.cpp b/src/odr/internal/odf/odf_spreadsheet.cpp deleted file mode 100644 index 168c5280..00000000 --- a/src/odr/internal/odf/odf_spreadsheet.cpp +++ /dev/null @@ -1,368 +0,0 @@ -#include - -#include -#include - -#include -#include - -namespace odr::internal::odf { - -void SheetIndex::init_column(const std::uint32_t column, - const std::uint32_t repeated, - const pugi::xml_node element) { - columns[column + repeated] = element; -} - -void SheetIndex::init_row(const std::uint32_t row, const std::uint32_t repeated, - const pugi::xml_node element) { - rows[row + repeated].row = element; -} - -void SheetIndex::init_cell(const std::uint32_t column, const std::uint32_t row, - const std::uint32_t columns_repeated, - const std::uint32_t rows_repeated, - const pugi::xml_node element) { - rows[row + rows_repeated].cells[column + columns_repeated] = element; -} - -pugi::xml_node SheetIndex::column(const std::uint32_t column) const { - if (const auto it = util::map::lookup_greater_than(columns, column); - it != std::end(columns)) { - return it->second; - } - return {}; -} - -pugi::xml_node SheetIndex::row(const std::uint32_t row) const { - if (const auto it = util::map::lookup_greater_than(rows, row); - it != std::end(rows)) { - return it->second.row; - } - return {}; -} - -pugi::xml_node SheetIndex::cell(const std::uint32_t column, - const std::uint32_t row) const { - if (const auto row_it = util::map::lookup_greater_than(rows, row); - row_it != std::end(rows)) { - const auto &cells = row_it->second.cells; - if (const auto cell_it = util::map::lookup_greater_than(cells, column); - cell_it != std::end(cells)) { - return cell_it->second; - } - } - return {}; -} - -class SheetCell final : public Element, public abstract::SheetCell { -public: - SheetCell(const pugi::xml_node node, const std::uint32_t column, - const std::uint32_t row, const bool is_repeated) - : Element(node), m_column{column}, m_row{row}, - m_is_repeated{is_repeated} {} - - [[nodiscard]] bool is_covered(const abstract::Document *) const override { - return std::strcmp(m_node.name(), "table:covered-table-cell") == 0; - } - - [[nodiscard]] TableDimensions - span(const abstract::Document *) const override { - return {m_node.attribute("table:number-rows-spanned").as_uint(1), - m_node.attribute("table:number-columns-spanned").as_uint(1)}; - } - - [[nodiscard]] ValueType - value_type(const abstract::Document *) const override { - if (const char *value_type = m_node.attribute("office:value-type").value(); - std::strcmp("float", value_type) == 0) { - return ValueType::float_number; - } - return ValueType::string; - } - - ResolvedStyle - partial_style(const abstract::Document *document) const override { - const auto *sheet = dynamic_cast(parent(document)); - return sheet->cell_style_(document, m_column, m_row); - } - - ResolvedStyle - intermediate_style(const abstract::Document *document) const override { - return partial_style(document); - } - - [[nodiscard]] TableCellStyle - style(const abstract::Document *document) const override { - return intermediate_style(document).table_cell_style; - } - - bool is_editable(const abstract::Document *) const override { - return !m_is_repeated; - } - -private: - std::uint32_t m_column{}; - std::uint32_t m_row{}; - bool m_is_repeated{}; -}; - -std::string Sheet::name(const abstract::Document *) const { - return m_node.attribute("table:name").value(); -} - -TableDimensions Sheet::dimensions(const abstract::Document *) const { - return m_index.dimensions; -} - -TableDimensions -Sheet::content(const abstract::Document *, - const std::optional range) const { - TableDimensions result; - - TableCursor cursor; - for (auto row : m_node.children("table:table-row")) { - const auto rows_repeated = - row.attribute("table:number-rows-repeated").as_uint(1); - cursor.add_row(rows_repeated); - - for (auto cell : row.children("table:table-cell")) { - const auto columns_repeated = - cell.attribute("table:number-columns-repeated").as_uint(1); - const auto colspan = - cell.attribute("table:number-columns-spanned").as_uint(1); - const auto rowspan = - cell.attribute("table:number-rows-spanned").as_uint(1); - cursor.add_cell(colspan, rowspan, columns_repeated); - - const std::uint32_t new_rows = cursor.row(); - if (const std::uint32_t new_cols = - std::max(result.columns, cursor.column()); - cell.first_child() && range && new_rows < range->rows && - new_cols < range->columns) { - result.rows = new_rows; - result.columns = new_cols; - } - } - } - - return result; -} - -ResolvedStyle Sheet::cell_style_(const abstract::Document *document, - const std::uint32_t column, - const std::uint32_t row) const { - const char *style_name = nullptr; - - const pugi::xml_node cell_node = m_index.cell(column, row); - if (const pugi::xml_attribute attr = - cell_node.attribute("table:style-name")) { - style_name = attr.value(); - } - - if (style_name == nullptr) { - const pugi::xml_node row_node = m_index.row(row); - if (const pugi::xml_attribute attr = - row_node.attribute("table:default-cell-style-name")) { - style_name = attr.value(); - } - } - if (style_name == nullptr) { - const pugi::xml_node column_node = m_index.column(column); - if (const pugi::xml_attribute attr = - column_node.attribute("table:default-cell-style-name")) { - style_name = attr.value(); - } - } - - if (style_name != nullptr) { - if (const Style *style = style_(document)->style(style_name); - style != nullptr) { - return style->resolved(); - } - } - - return {}; -} - -abstract::SheetCell *Sheet::cell(const abstract::Document *, - const std::uint32_t column, - const std::uint32_t row) const { - if (const auto cell_it = m_cells.find({column, row}); - cell_it != std::end(m_cells)) { - return cell_it->second; - } - return nullptr; -} - -abstract::Element *Sheet::first_shape(const abstract::Document *) const { - return m_first_shape; -} - -TableStyle Sheet::style(const abstract::Document *document) const { - return partial_style(document).table_style; -} - -TableColumnStyle Sheet::column_style(const abstract::Document *document, - const std::uint32_t column) const { - if (const pugi::xml_node column_node = m_index.column(column); column_node) { - if (const pugi::xml_attribute attr = - column_node.attribute("table:style-name")) { - if (const Style *style = style_(document)->style(attr.value()); - style != nullptr) { - return style->resolved().table_column_style; - } - } - } - return {}; -} - -TableRowStyle Sheet::row_style(const abstract::Document *document, - const std::uint32_t row) const { - if (const pugi::xml_node column_node = m_index.row(row); column_node) { - if (const pugi::xml_attribute attr = - column_node.attribute("table:style-name")) { - if (const Style *style = style_(document)->style(attr.value()); - style != nullptr) { - return style->resolved().table_row_style; - } - } - } - return {}; -} - -TableCellStyle Sheet::cell_style(const abstract::Document *document, - const std::uint32_t column, - const std::uint32_t row) const { - return cell_style_(document, column, row).table_cell_style; -} - -void Sheet::init_column_(const std::uint32_t column, - const std::uint32_t repeated, - const pugi::xml_node element) { - m_index.init_column(column, repeated, element); -} - -void Sheet::init_row_(const std::uint32_t row, const std::uint32_t repeated, - const pugi::xml_node element) { - m_index.init_row(row, repeated, element); -} - -void Sheet::init_cell_(const std::uint32_t column, const std::uint32_t row, - const std::uint32_t columns_repeated, - const std::uint32_t rows_repeated, - const pugi::xml_node element) { - m_index.init_cell(column, row, columns_repeated, rows_repeated, element); -} - -void Sheet::init_cell_element_(const std::uint32_t column, - const std::uint32_t row, SheetCell *element) { - m_cells[{column, row}] = element; - element->m_parent = this; -} - -void Sheet::init_dimensions_(const TableDimensions dimensions) { - m_index.dimensions = dimensions; -} - -void Sheet::append_shape_(Element *shape) { - shape->m_previous_sibling = m_last_shape; - shape->m_parent = this; - if (m_last_shape == nullptr) { - m_first_shape = shape; - } else { - m_last_shape->m_next_sibling = shape; - } - m_last_shape = shape; -} - -} // namespace odr::internal::odf - -namespace odr::internal { - -template <> -std::tuple -odf::parse_element_tree(Document &document, pugi::xml_node node) { - if (!node) { - return std::make_tuple(nullptr, pugi::xml_node()); - } - - auto sheet_unique = std::make_unique(node); - auto &sheet = *sheet_unique; - document.register_element_(std::move(sheet_unique)); - - TableDimensions dimensions; - TableCursor cursor; - - for (auto column_node : node.children("table:table-column")) { - const auto columns_repeated = - column_node.attribute("table:number-columns-repeated").as_uint(1); - - sheet.init_column_(cursor.column(), columns_repeated, column_node); - - cursor.add_column(columns_repeated); - } - - dimensions.columns = cursor.column(); - cursor = {}; - - for (auto row_node : node.children("table:table-row")) { - const auto rows_repeated = - row_node.attribute("table:number-rows-repeated").as_uint(1); - - sheet.init_row_(cursor.row(), rows_repeated, row_node); - - // TODO covered cells - for (auto cell_node : row_node.children("table:table-cell")) { - const auto columns_repeated = - cell_node.attribute("table:number-columns-repeated").as_uint(1); - const auto colspan = - cell_node.attribute("table:number-columns-spanned").as_uint(1); - const auto rowspan = - cell_node.attribute("table:number-rows-spanned").as_uint(1); - const bool is_repeated = columns_repeated > 1 || rows_repeated > 1; - - sheet.init_cell_(cursor.column(), cursor.row(), columns_repeated, - rows_repeated, cell_node); - - bool empty = false; - if (!cell_node.first_child()) { - empty = true; - } - - if (!empty) { - for (std::uint32_t row_repeat = 0; row_repeat < rows_repeated; - ++row_repeat) { - for (std::uint32_t column_repeat = 0; - column_repeat < columns_repeated; ++column_repeat) { - auto [cell, _] = parse_element_tree( - document, cell_node, cursor.column() + column_repeat, - cursor.row() + row_repeat, is_repeated); - sheet.init_cell_element_(cursor.column() + column_repeat, - cursor.row() + row_repeat, cell); - } - } - } - - cursor.add_cell(colspan, rowspan, columns_repeated); - } - - cursor.add_row(rows_repeated); - } - - dimensions.rows = cursor.row(); - - sheet.init_dimensions_(dimensions); - - for (const pugi::xml_node shape_node : - node.child("table:shapes").children()) { - if (auto [shape, _] = parse_any_element_tree(document, shape_node); - shape != nullptr) { - sheet.append_shape_(shape); - } - } - - return std::make_tuple(&sheet, node.next_sibling()); -} - -} // namespace odr::internal diff --git a/src/odr/internal/odf/odf_spreadsheet.hpp b/src/odr/internal/odf/odf_spreadsheet.hpp deleted file mode 100644 index 574f201c..00000000 --- a/src/odr/internal/odf/odf_spreadsheet.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include - -namespace pugi { -class xml_node; -} - -namespace odr::internal::odf { -class Document; -class SheetCell; - -class SpreadsheetRoot final : public Root { -public: - using Root::Root; -}; - -struct SheetIndex final { - struct Row { - pugi::xml_node row; - std::map cells; - }; - - TableDimensions dimensions; - - std::map columns; - std::map rows; - - void init_column(std::uint32_t column, std::uint32_t repeated, - pugi::xml_node element); - void init_row(std::uint32_t row, std::uint32_t repeated, - pugi::xml_node element); - void init_cell(std::uint32_t column, std::uint32_t row, - std::uint32_t columns_repeated, std::uint32_t rows_repeated, - pugi::xml_node element); - - [[nodiscard]] pugi::xml_node column(std::uint32_t) const; - [[nodiscard]] pugi::xml_node row(std::uint32_t) const; - [[nodiscard]] pugi::xml_node cell(std::uint32_t column, - std::uint32_t row) const; -}; - -class Sheet final : public Element, public abstract::Sheet { -public: - using Element::Element; - - [[nodiscard]] std::string name(const abstract::Document *) const override; - - [[nodiscard]] TableDimensions - dimensions(const abstract::Document *) const override; - - [[nodiscard]] TableDimensions - content(const abstract::Document *, - std::optional range) const override; - - abstract::SheetCell *cell(const abstract::Document *, std::uint32_t column, - std::uint32_t row) const override; - - [[nodiscard]] abstract::Element * - first_shape(const abstract::Document *) const override; - - [[nodiscard]] TableStyle style(const abstract::Document *) const override; - [[nodiscard]] TableColumnStyle - column_style(const abstract::Document *, std::uint32_t column) const override; - [[nodiscard]] TableRowStyle row_style(const abstract::Document *, - std::uint32_t row) const override; - [[nodiscard]] TableCellStyle cell_style(const abstract::Document *, - std::uint32_t column, - std::uint32_t row) const override; - - void init_column_(std::uint32_t column, std::uint32_t repeated, - pugi::xml_node element); - void init_row_(std::uint32_t row, std::uint32_t repeated, - pugi::xml_node element); - void init_cell_(std::uint32_t column, std::uint32_t row, - std::uint32_t columns_repeated, std::uint32_t rows_repeated, - pugi::xml_node element); - void init_cell_element_(std::uint32_t column, std::uint32_t row, - SheetCell *element); - void init_dimensions_(TableDimensions dimensions); - void append_shape_(Element *shape); - - ResolvedStyle cell_style_(const abstract::Document *, std::uint32_t column, - std::uint32_t row) const; - -private: - SheetIndex m_index; - - std::unordered_map m_cells; - Element *m_first_shape{nullptr}; - Element *m_last_shape{nullptr}; -}; - -template <> -std::tuple -parse_element_tree(Document &document, pugi::xml_node node); - -} // namespace odr::internal::odf diff --git a/src/odr/internal/odf/odf_style.cpp b/src/odr/internal/odf/odf_style.cpp index 2a632cc4..d2fb94a1 100644 --- a/src/odr/internal/odf/odf_style.cpp +++ b/src/odr/internal/odf/odf_style.cpp @@ -1,8 +1,9 @@ +#include "odf_document.hpp" + #include #include -#include #include #include @@ -556,7 +557,7 @@ Style *StyleRegistry::generate_style_(const std::string &name, void StyleRegistry::generate_master_pages_(Document &document) { for (const auto &[name, node] : m_index_master_page) { m_master_page_elements[name] = - dynamic_cast(parse_tree(document, node)); + parse_tree(document.element_registry(), node); } if (m_first_master_page) { @@ -588,7 +589,8 @@ pugi::xml_node StyleRegistry::font_face_node(const std::string &name) const { return {}; } -MasterPage *StyleRegistry::master_page(const std::string &name) const { +ExtendedElementIdentifier +StyleRegistry::master_page(const std::string &name) const { if (const auto master_page_elements_it = m_master_page_elements.find(name); master_page_elements_it != std::end(m_master_page_elements)) { return master_page_elements_it->second; @@ -596,7 +598,7 @@ MasterPage *StyleRegistry::master_page(const std::string &name) const { return {}; } -MasterPage *StyleRegistry::first_master_page() const { +ExtendedElementIdentifier StyleRegistry::first_master_page() const { return m_first_master_page_element; } diff --git a/src/odr/internal/odf/odf_style.hpp b/src/odr/internal/odf/odf_style.hpp index edbd24c2..e789a5b1 100644 --- a/src/odr/internal/odf/odf_style.hpp +++ b/src/odr/internal/odf/odf_style.hpp @@ -1,7 +1,8 @@ #pragma once +#include + #include -#include #include #include @@ -9,6 +10,8 @@ #include #include +#include + namespace odr { struct PageLayout; struct GraphicStyle; @@ -73,8 +76,9 @@ class StyleRegistry final { [[nodiscard]] pugi::xml_node font_face_node(const std::string &name) const; - [[nodiscard]] MasterPage *master_page(const std::string &name) const; - [[nodiscard]] MasterPage *first_master_page() const; + [[nodiscard]] ExtendedElementIdentifier + master_page(const std::string &name) const; + [[nodiscard]] ExtendedElementIdentifier first_master_page() const; private: std::unordered_map m_index_font_face; @@ -89,8 +93,9 @@ class StyleRegistry final { std::unordered_map> m_default_styles; std::unordered_map> m_styles; - std::unordered_map m_master_page_elements; - MasterPage *m_first_master_page_element{}; + std::unordered_map + m_master_page_elements; + ExtendedElementIdentifier m_first_master_page_element{}; void generate_indices_(pugi::xml_node content_root, pugi::xml_node styles_root); diff --git a/src/odr/internal/ooxml/presentation/ooxml_presentation_element.hpp b/src/odr/internal/ooxml/presentation/ooxml_presentation_element.hpp index bdb9408a..ba10b176 100644 --- a/src/odr/internal/ooxml/presentation/ooxml_presentation_element.hpp +++ b/src/odr/internal/ooxml/presentation/ooxml_presentation_element.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include