diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2022-06-06 19:48:03 -0400 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2022-06-06 21:32:38 -0400 |
commit | 8ec42c299640fc7793f04f2e8b013233a32cbe03 (patch) | |
tree | 433d0c0a6427daae58e6dba9e3d77d22a9e5a365 | |
parent | 2a6263ff4bcb195d7e9c398f5644511b43801730 (diff) | |
download | orcus-8ec42c299640fc7793f04f2e8b013233a32cbe03.tar.gz |
Add import_xf sub-interface and use it in xlsx
-rw-r--r-- | include/orcus/spreadsheet/factory.hpp | 25 | ||||
-rw-r--r-- | include/orcus/spreadsheet/import_interface_styles.hpp | 37 | ||||
-rw-r--r-- | src/liborcus/spreadsheet_interface.cpp | 2 | ||||
-rw-r--r-- | src/liborcus/xlsx_context.cpp | 198 | ||||
-rw-r--r-- | src/liborcus/xlsx_context.hpp | 2 | ||||
-rw-r--r-- | src/spreadsheet/factory_styles.cpp | 112 |
6 files changed, 297 insertions, 79 deletions
diff --git a/include/orcus/spreadsheet/factory.hpp b/include/orcus/spreadsheet/factory.hpp index 8078fa6b..9ec2f882 100644 --- a/include/orcus/spreadsheet/factory.hpp +++ b/include/orcus/spreadsheet/factory.hpp @@ -79,6 +79,7 @@ public: virtual iface::import_border_style* get_border_style() override; virtual iface::import_cell_protection* get_cell_protection() override; virtual iface::import_number_format* get_number_format() override; + virtual iface::import_xf* get_xf(xf_category_t cat) override; virtual void set_font_count(size_t n) override; virtual void set_fill_count(size_t n) override; @@ -210,6 +211,30 @@ public: void reset(); }; +class ORCUS_SPM_DLLPUBLIC import_xf : public iface::import_xf +{ + struct impl; + std::unique_ptr<impl> mp_impl; + +public: + import_xf() = delete; + import_xf(styles& _styles_model, string_pool& sp); + virtual ~import_xf() override; + + virtual void set_font(size_t index) override; + virtual void set_fill(size_t index) override; + virtual void set_border(size_t index) override; + virtual void set_protection(size_t index) override; + virtual void set_number_format(size_t index) override; + virtual void set_style_xf(size_t index) override; + virtual void set_apply_alignment(bool b) override; + virtual void set_horizontal_alignment(hor_alignment_t align) override; + virtual void set_vertical_alignment(ver_alignment_t align) override; + virtual size_t commit() override; + + void reset(xf_category_t cat); +}; + class ORCUS_SPM_DLLPUBLIC export_factory : public iface::export_factory { struct impl; diff --git a/include/orcus/spreadsheet/import_interface_styles.hpp b/include/orcus/spreadsheet/import_interface_styles.hpp index 0ae60323..6509673a 100644 --- a/include/orcus/spreadsheet/import_interface_styles.hpp +++ b/include/orcus/spreadsheet/import_interface_styles.hpp @@ -24,6 +24,7 @@ class import_fill_style; class import_border_style; class import_cell_protection; class import_number_format; +class import_xf; /** * Interface for styles. Note that because the default style must have an @@ -94,6 +95,17 @@ public: virtual import_number_format* get_number_format() = 0; /** + * Return a pointer to the interface instance for importing cell format + * (xf) indices that each references different format attributes in their + * respective pools. Note that the import_styles implementer <i>must</i> + * return a non-null pointer. + * + * @return pointer to the interface instance for importing cell format (xf) + * indices. + */ + virtual import_xf* get_xf(xf_category_t cat) = 0; + + /** * Set the total number of font styles. This may be called before importing * any of the font styles. This will give the implementer a chance to * allocate storage. Note that it may not always be called. @@ -294,6 +306,31 @@ public: virtual size_t commit() = 0; }; +class ORCUS_DLLPUBLIC import_xf +{ +public: + virtual ~import_xf(); + + virtual void set_font(size_t index) = 0; + virtual void set_fill(size_t index) = 0; + virtual void set_border(size_t index) = 0; + virtual void set_protection(size_t index) = 0; + virtual void set_number_format(size_t index) = 0; + + /** + * Set the index into the cell style record to specify a named cell style it + * uses as its basis. + * + * @param index index into the cell style record it uses as its basis. + */ + virtual void set_style_xf(size_t index) = 0; + virtual void set_apply_alignment(bool b) = 0; + virtual void set_horizontal_alignment(hor_alignment_t align) = 0; + virtual void set_vertical_alignment(ver_alignment_t align) = 0; + + virtual size_t commit() = 0; +}; + }}} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/src/liborcus/spreadsheet_interface.cpp b/src/liborcus/spreadsheet_interface.cpp index 2ffbb855..91775f04 100644 --- a/src/liborcus/spreadsheet_interface.cpp +++ b/src/liborcus/spreadsheet_interface.cpp @@ -35,6 +35,8 @@ import_cell_protection::~import_cell_protection() {} import_number_format::~import_number_format() {} +import_xf::~import_xf() {} + import_sheet_properties::~import_sheet_properties() {} import_named_expression::~import_named_expression() {} diff --git a/src/liborcus/xlsx_context.cpp b/src/liborcus/xlsx_context.cpp index bfbdb696..9496a7f9 100644 --- a/src/liborcus/xlsx_context.cpp +++ b/src/liborcus/xlsx_context.cpp @@ -400,65 +400,6 @@ public: } }; -class xf_attr_parser -{ - spreadsheet::iface::import_styles& m_styles; -public: - xf_attr_parser(spreadsheet::iface::import_styles& styles) : - m_styles(styles) {} - - void operator() (const xml_token_attr_t& attr) - { - switch (attr.name) - { - case XML_borderId: - { - size_t n = to_long(attr.value); - m_styles.set_xf_border(n); - } - break; - case XML_fillId: - { - size_t n = to_long(attr.value); - m_styles.set_xf_fill(n); - } - break; - case XML_fontId: - { - size_t n = to_long(attr.value); - m_styles.set_xf_font(n); - } - break; - case XML_numFmtId: - { - size_t n = to_long(attr.value); - m_styles.set_xf_number_format(n); - } - break; - case XML_xfId: - { - size_t n = to_long(attr.value); - m_styles.set_xf_style_xf(n); - } - break; - case XML_applyBorder: - break; - case XML_applyFill: - break; - case XML_applyFont: - break; - case XML_applyNumberFormat: - break; - case XML_applyAlignment: - { - bool b = to_long(attr.value) != 0; - m_styles.set_xf_apply_alignment(b); - } - break; - } - } -}; - class cell_alignment_attr_parser { spreadsheet::hor_alignment_t m_hor_align; @@ -828,6 +769,7 @@ void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const x mp_styles->set_xf_count(ss::xf_category_t::cell_style, n); } m_cell_style_xf = true; + mp_xf = mp_styles->get_xf(ss::xf_category_t::cell_style); break; } case XML_cellXfs: @@ -842,6 +784,7 @@ void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const x mp_styles->set_xf_count(ss::xf_category_t::cell, n); } m_cell_style_xf = false; + mp_xf = mp_styles->get_xf(ss::xf_category_t::cell); break; } case XML_dxfs: @@ -855,6 +798,7 @@ void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const x size_t n = strtoul(ps.data(), nullptr, 10); mp_styles->set_xf_count(ss::xf_category_t::differential, n); } + mp_xf = mp_styles->get_xf(ss::xf_category_t::differential); break; } case XML_cellStyles: @@ -878,17 +822,72 @@ void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const x } case XML_xf: { + assert(mp_xf); + // Actual cell format attributes (for some reason) abbreviated to // 'xf'. Used both by cells and cell styles. - xml_elem_stack_t allowed; - allowed.push_back(xml_elem_stack_t::value_type(NS_ooxml_xlsx, XML_cellXfs)); - allowed.push_back(xml_elem_stack_t::value_type(NS_ooxml_xlsx, XML_cellStyleXfs)); - xml_element_expected(parent, allowed); + const xml_elem_set_t expected = { + { NS_ooxml_xlsx, XML_cellXfs }, + { NS_ooxml_xlsx, XML_cellStyleXfs }, + }; + xml_element_expected(parent, expected); + + for (const xml_token_attr_t& attr : attrs) + { + switch (attr.name) + { + case XML_borderId: + { + size_t n = to_long(attr.value); + mp_xf->set_border(n); + break; + } + case XML_fillId: + { + size_t n = to_long(attr.value); + mp_xf->set_fill(n); + break; + } + case XML_fontId: + { + size_t n = to_long(attr.value); + mp_xf->set_font(n); + break; + } + case XML_numFmtId: + { + size_t n = to_long(attr.value); + mp_xf->set_number_format(n); + break; + } + case XML_xfId: + { + size_t n = to_long(attr.value); + mp_xf->set_style_xf(n); + break; + } + case XML_applyBorder: + break; + case XML_applyFill: + break; + case XML_applyFont: + break; + case XML_applyNumberFormat: + break; + case XML_applyAlignment: + { + bool b = to_long(attr.value) != 0; + mp_xf->set_apply_alignment(b); + break; + } + } + } - for_each(attrs.begin(), attrs.end(), xf_attr_parser(*mp_styles)); break; } case XML_dxf: + // TODO: Pick up dxf record. Technically dxf is a sub set of xf, + // but for now we use xf for dxf. break; case XML_protection: { @@ -925,14 +924,56 @@ void xlsx_styles_context::start_element(xmlns_id_t ns, xml_token_t name, const x } case XML_alignment: { - xml_elem_stack_t expected_elements; - expected_elements.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_xf)); - expected_elements.push_back(xml_token_pair_t(NS_ooxml_xlsx, XML_dxf)); - xml_element_expected(parent, expected_elements); - cell_alignment_attr_parser func; - func = for_each(attrs.begin(), attrs.end(), func); - mp_styles->set_xf_horizontal_alignment(func.get_hor_align()); - mp_styles->set_xf_vertical_alignment(func.get_ver_align()); + assert(mp_xf); + const xml_elem_set_t expected = { + { NS_ooxml_xlsx, XML_xf }, + { NS_ooxml_xlsx, XML_dxf }, + }; + xml_element_expected(parent, expected); + + // NB: default vertical alignment is 'bottom'. + ss::hor_alignment_t hor_align = ss::hor_alignment_t::unknown; + ss::ver_alignment_t ver_align = ss::ver_alignment_t::bottom; + + for (const xml_token_attr_t& attr : attrs) + { + switch (attr.name) + { + case XML_horizontal: + { + if (attr.value == "center") + hor_align = ss::hor_alignment_t::center; + else if (attr.value == "right") + hor_align = ss::hor_alignment_t::right; + else if (attr.value == "left") + hor_align = ss::hor_alignment_t::left; + else if (attr.value == "justify") + hor_align = ss::hor_alignment_t::justified; + else if (attr.value == "distributed") + hor_align = ss::hor_alignment_t::distributed; + break; + } + case XML_vertical: + { + if (attr.value == "top") + ver_align = ss::ver_alignment_t::top; + else if (attr.value == "center") + ver_align = ss::ver_alignment_t::middle; + else if (attr.value == "bottom") + ver_align = ss::ver_alignment_t::bottom; + else if (attr.value == "justify") + ver_align = ss::ver_alignment_t::justified; + else if (attr.value == "distributed") + ver_align = ss::ver_alignment_t::distributed; + break; + } + default: + ; + } + } + + mp_xf->set_horizontal_alignment(hor_align); + mp_xf->set_vertical_alignment(ver_align); break; } case XML_numFmts: @@ -986,14 +1027,15 @@ bool xlsx_styles_context::end_element(xmlns_id_t ns, xml_token_t name) case XML_cellStyle: mp_styles->commit_cell_style(); break; - case XML_xf: - if (m_cell_style_xf) - mp_styles->commit_cell_style_xf(); - else - mp_styles->commit_cell_xf(); + case XML_cellStyleXfs: + case XML_cellXfs: + case XML_dxfs: + mp_xf = nullptr; break; + case XML_xf: case XML_dxf: - mp_styles->commit_dxf(); + assert(mp_xf); + mp_xf->commit(); break; case XML_protection: { diff --git a/src/liborcus/xlsx_context.hpp b/src/liborcus/xlsx_context.hpp index 30615d06..75c56a4b 100644 --- a/src/liborcus/xlsx_context.hpp +++ b/src/liborcus/xlsx_context.hpp @@ -26,6 +26,7 @@ namespace spreadsheet { namespace iface { class import_border_style; class import_cell_protection; class import_number_format; + class import_xf; }} /** @@ -86,6 +87,7 @@ private: spreadsheet::iface::import_border_style* mp_border = nullptr; spreadsheet::iface::import_cell_protection* mp_protection = nullptr; spreadsheet::iface::import_number_format* mp_numfmt = nullptr; + spreadsheet::iface::import_xf* mp_xf = nullptr; string_pool m_pool; bool m_diagonal_up; diff --git a/src/spreadsheet/factory_styles.cpp b/src/spreadsheet/factory_styles.cpp index 773091e4..2249fb60 100644 --- a/src/spreadsheet/factory_styles.cpp +++ b/src/spreadsheet/factory_styles.cpp @@ -37,6 +37,7 @@ struct import_styles::impl import_border_style border_style; import_cell_protection cell_protection; import_number_format number_format; + import_xf xf; cell_format_t cur_cell_format; cell_style_t cur_cell_style; @@ -48,7 +49,8 @@ struct import_styles::impl fill_style(_styles_model, sp), border_style(_styles_model, sp), cell_protection(_styles_model, sp), - number_format(_styles_model, sp) + number_format(_styles_model, sp), + xf(_styles_model, sp) {} }; @@ -87,6 +89,12 @@ iface::import_number_format* import_styles::get_number_format() return &mp_impl->number_format; } +iface::import_xf* import_styles::get_xf(xf_category_t cat) +{ + mp_impl->xf.reset(cat); + return &mp_impl->xf; +} + void import_styles::set_font_count(size_t n) { mp_impl->styles_model.reserve_font_store(n); @@ -625,6 +633,108 @@ void import_number_format::reset() mp_impl->cur_numfmt_active.reset(); } +struct import_xf::impl +{ + styles& styles_model; + string_pool& str_pool; + + cell_format_t cur_cell_format; + xf_category_t xf_category = xf_category_t::unknown; + + impl(styles& _styles_model, string_pool& sp) : + styles_model(_styles_model), str_pool(sp) {} +}; + +import_xf::import_xf(styles& _styles_model, string_pool& sp) : + mp_impl(std::make_unique<impl>(_styles_model, sp)) +{ +} + +import_xf::~import_xf() +{ +} + +void import_xf::set_font(size_t index) +{ + mp_impl->cur_cell_format.font = index; +} + +void import_xf::set_fill(size_t index) +{ + mp_impl->cur_cell_format.fill = index; +} + +void import_xf::set_border(size_t index) +{ + mp_impl->cur_cell_format.border = index; + + // TODO : we need to decide whether to have interface methods for these + // apply_foo attributes. For now there is only one, for alignment. + mp_impl->cur_cell_format.apply_border = index > 0; +} + +void import_xf::set_protection(size_t index) +{ + mp_impl->cur_cell_format.protection = index; +} + +void import_xf::set_number_format(size_t index) +{ + mp_impl->cur_cell_format.number_format = index; +} + +void import_xf::set_style_xf(size_t index) +{ + mp_impl->cur_cell_format.style_xf = index; +} + +void import_xf::set_apply_alignment(bool b) +{ + mp_impl->cur_cell_format.apply_alignment = b; +} + +void import_xf::set_horizontal_alignment(hor_alignment_t align) +{ + mp_impl->cur_cell_format.hor_align = align; +} + +void import_xf::set_vertical_alignment(ver_alignment_t align) +{ + mp_impl->cur_cell_format.ver_align = align; +} + +size_t import_xf::commit() +{ + size_t xf_id = 0; + + switch (mp_impl->xf_category) + { + case xf_category_t::cell: + xf_id = mp_impl->styles_model.append_cell_format(mp_impl->cur_cell_format); + break; + case xf_category_t::cell_style: + xf_id = mp_impl->styles_model.append_cell_style_format(mp_impl->cur_cell_format); + break; + case xf_category_t::differential: + xf_id = mp_impl->styles_model.append_diff_cell_format(mp_impl->cur_cell_format); + break; + case xf_category_t::unknown: + throw std::logic_error("unknown cell format category"); + } + + mp_impl->cur_cell_format.reset(); + return xf_id; +} + +void import_xf::reset(xf_category_t cat) +{ + if (cat == xf_category_t::unknown) + throw std::invalid_argument("The specified category is 'unknown'."); + + mp_impl->cur_cell_format.reset(); + mp_impl->xf_category = cat; +} + }} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |