diff --git a/include/orcus/spreadsheet/import_interface.hpp b/include/orcus/spreadsheet/import_interface.hpp index 66da60aaef5ff352dd9523176dfaabd89b0c3797..0ff96f8c870dd1fcac2003d999876139c72a3cb5 100644 --- a/include/orcus/spreadsheet/import_interface.hpp +++ b/include/orcus/spreadsheet/import_interface.hpp @@ -13,6 +13,7 @@ #include "types.hpp" #include "orcus/types.hpp" #include "orcus/env.hpp" +#include // NB: This header must not depend on ixion, as it needs to be usable for // those clients that provide their own formula engine. Other headers in @@ -110,6 +111,7 @@ public: virtual void set_border_style(orcus::spreadsheet::border_direction_t dir, border_style_t style) = 0; virtual void set_border_color( orcus::spreadsheet::border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue) = 0; + virtual void set_border_width(border_direction_t dir, length_t width) = 0; virtual size_t commit_border() = 0; // cell protection diff --git a/include/orcus/spreadsheet/styles.hpp b/include/orcus/spreadsheet/styles.hpp index 8ce834cf051c8917c98c2248b9a4ab2c3cea2ca1..3cf019e739368d723bfcb9b7b0eb558224a93bc3 100644 --- a/include/orcus/spreadsheet/styles.hpp +++ b/include/orcus/spreadsheet/styles.hpp @@ -11,7 +11,7 @@ #include "orcus/spreadsheet/import_interface.hpp" #include "orcus/pstring.hpp" #include "orcus/env.hpp" - +#include #include namespace orcus { @@ -60,6 +60,7 @@ struct ORCUS_SPM_DLLPUBLIC border_attrs_t { border_style_t style; color_t border_color; + length_t border_width; border_attrs_t(); void reset(); @@ -72,6 +73,8 @@ struct ORCUS_SPM_DLLPUBLIC border_t border_attrs_t left; border_attrs_t right; border_attrs_t diagonal; + border_attrs_t diagonal_bl_tr; + border_attrs_t diagonal_tl_br; border_t(); void reset(); @@ -157,6 +160,7 @@ public: virtual void set_border_style(border_direction_t dir, border_style_t style); virtual void set_border_color( border_direction_t dir, color_elem_t alpha, color_elem_t red, color_elem_t green, color_elem_t blue); + virtual void set_border_width(border_direction_t dir,length_t length); virtual size_t commit_border(); virtual void set_cell_hidden(bool b); diff --git a/include/orcus/spreadsheet/types.hpp b/include/orcus/spreadsheet/types.hpp index 46949539f3c401be3eabff310e1cbd2c996ee04d..9b4987f111c336e02e0f46026c406ccbe6eb50c3 100644 --- a/include/orcus/spreadsheet/types.hpp +++ b/include/orcus/spreadsheet/types.hpp @@ -33,13 +33,16 @@ enum class border_direction_t bottom, left, right, - diagonal + diagonal, + diagonal_bl_tr, + diagonal_tl_br }; enum class border_style_t { unknown = 0, none, + solid, dash_dot, dash_dot_dot, dashed, diff --git a/src/liborcus/odf_helper.cpp b/src/liborcus/odf_helper.cpp index fc3f61e5bc957e6e9291cec9f172dfb8762d1002..b21ecbb5151397ed840780c55bb2690d59c5b5ae 100644 --- a/src/liborcus/odf_helper.cpp +++ b/src/liborcus/odf_helper.cpp @@ -6,11 +6,41 @@ */ #include "odf_helper.hpp" +#include "string_helper.hpp" +#include +#include +#include +#include +#include +#include namespace orcus { namespace { +typedef mdds::sorted_string_map odf_border_style_map; + +odf_border_style_map::entry odf_border_style_entries[] = +{ + { MDDS_ASCII("unknown") , spreadsheet::border_style_t::unknown}, + { MDDS_ASCII("none") , spreadsheet::border_style_t::none}, + { MDDS_ASCII("solid") ,spreadsheet::border_style_t::solid}, + { MDDS_ASCII("dash_dot") , spreadsheet::border_style_t::dash_dot}, + { MDDS_ASCII("dash_dot_dot") , spreadsheet::border_style_t::dash_dot_dot}, + { MDDS_ASCII("dashed") , spreadsheet::border_style_t::dashed}, + { MDDS_ASCII("dotted") , spreadsheet::border_style_t::dotted}, + { MDDS_ASCII("double_border") , spreadsheet::border_style_t::double_border}, + { MDDS_ASCII("hair") , spreadsheet::border_style_t::hair}, + { MDDS_ASCII("medium") , spreadsheet::border_style_t::medium}, + { MDDS_ASCII("medium_dash_dot") , spreadsheet::border_style_t::medium_dash_dot}, + { MDDS_ASCII("medium_dash_dot_dot") , spreadsheet::border_style_t::medium_dash_dot_dot}, + { MDDS_ASCII("medium_dashed") , spreadsheet::border_style_t::medium_dashed}, + { MDDS_ASCII("slant_dash_dot") , spreadsheet::border_style_t::slant_dash_dot}, + { MDDS_ASCII("thick") , spreadsheet::border_style_t::thick}, + { MDDS_ASCII("thin") , spreadsheet::border_style_t::thin} +}; + + bool is_valid_hex_digit(const char& character, orcus::spreadsheet::color_elem_t& val) { if ('0' <= character && character <= '9') @@ -66,7 +96,33 @@ bool odf_helper::convert_fo_color(const pstring& value, orcus::spreadsheet::colo return convert_color_digits(value, blue, 5); } - + +orcus::odf_helper::odf_border_details odf_helper::extract_border_details(const orcus::pstring &value) +{ + orcus::pstring color_code; + orcus::pstring width; + orcus::pstring style; + orcus::odf_helper::odf_border_details border_details; + + std::vector detail = orcus::string_helper::split_string(value,' '); + + for(auto& sub_detail : detail) + { + if(sub_detail[0] == '#') + convert_fo_color(sub_detail , border_details.red , border_details.green , border_details.blue); + + else if(sub_detail[0] >= '0' && sub_detail[0] <='9') + border_details.border_width = orcus::to_length(sub_detail); + + else // This has to be a style + { + odf_border_style_map border_style_map(odf_border_style_entries , ORCUS_N_ELEMENTS(odf_border_style_entries) , spreadsheet::border_style_t::none); + border_details.border_style = border_style_map.find(sub_detail.get() , sub_detail.size()); + } + + } + return border_details; +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/src/liborcus/odf_helper.hpp b/src/liborcus/odf_helper.hpp index 6880914c5e1485451a9f6addefd8d158ef7fe8ca..a3273b437c5d5021c50807b49feb5a9088121492 100644 --- a/src/liborcus/odf_helper.hpp +++ b/src/liborcus/odf_helper.hpp @@ -10,15 +10,32 @@ #include #include +#include +#include namespace orcus { class odf_helper { public: + struct odf_border_details + { + + orcus::spreadsheet::border_style_t border_style; + + spreadsheet::color_elem_t red; + spreadsheet::color_elem_t green; + spreadsheet::color_elem_t blue; + + length_t border_width; + }; + static bool convert_fo_color(const orcus::pstring& value, orcus::spreadsheet::color_elem_t& red, orcus::spreadsheet::color_elem_t& green, orcus::spreadsheet::color_elem_t& blue); + /* extracts border style,width and colors out of the pstring provided to it */ + static orcus::odf_helper::odf_border_details extract_border_details(const orcus::pstring& value); + }; } diff --git a/src/liborcus/odf_styles_context.cpp b/src/liborcus/odf_styles_context.cpp index 6cf726982a47733e4215bc1281de781f4fd1bd82..2ee518829fce626c32bf7b434a3992e724a69a21 100644 --- a/src/liborcus/odf_styles_context.cpp +++ b/src/liborcus/odf_styles_context.cpp @@ -9,7 +9,6 @@ #include "odf_namespace_types.hpp" #include "odf_token_constants.hpp" #include "odf_helper.hpp" - #include "orcus/measurement.hpp" #include "orcus/spreadsheet/import_interface.hpp" @@ -163,12 +162,19 @@ public: class cell_prop_attr_parser : std::unary_function { +public: + typedef std::map border_map_t; + odf_helper::odf_border_details border_details; +private: spreadsheet::color_elem_t m_background_red; spreadsheet::color_elem_t m_background_green; spreadsheet::color_elem_t m_background_blue; + bool m_background_color; + border_map_t m_border_style_dir_pair; + public: void operator() (const xml_token_attr_t& attr) @@ -181,6 +187,46 @@ public: m_background_color = odf_helper::convert_fo_color(attr.value, m_background_red, m_background_green, m_background_blue); break; + + case XML_border: + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::top , border_details)); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::bottom , border_details)); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::left , border_details)); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::right , border_details)); + break; + + case XML_border_top: + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::top , border_details)); + break; + + case XML_border_bottom: + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::bottom , border_details)); + break; + + case XML_border_left: + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::left , border_details)); + break; + + case XML_border_right: + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::right , border_details)); + break; + case XML_diagonal_bl_tr: + { + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::diagonal_bl_tr , border_details)); + } + break; + case XML_diagonal_tl_br: + { + border_details = odf_helper::extract_border_details(attr.value); + m_border_style_dir_pair.insert(std::make_pair(spreadsheet::border_direction_t::diagonal_tl_br , border_details)); + } + default: ; } @@ -188,6 +234,7 @@ public: } bool has_background_color() { return m_background_color; } + void get_background_color(spreadsheet::color_elem_t& red, spreadsheet::color_elem_t& green, spreadsheet::color_elem_t& blue) { @@ -195,6 +242,14 @@ public: green = m_background_green; blue = m_background_blue; } + + bool has_border() { return !m_border_style_dir_pair.empty(); } + + border_map_t& get_border_attrib() + { + return m_border_style_dir_pair; + } + }; } @@ -370,9 +425,9 @@ void styles_context::start_element(xmlns_id_t ns, xml_token_t name, const std::v m_current_style->cell_data->automatic_style = m_automatic_styles; if (mp_styles) { + cell_prop_attr_parser func; func = std::for_each(attrs.begin(), attrs.end(), func); - if (func.has_background_color()) { spreadsheet::color_elem_t red, green, blue; @@ -380,15 +435,33 @@ void styles_context::start_element(xmlns_id_t ns, xml_token_t name, const std::v mp_styles->set_fill_bg_color(0, red, green, blue); } - size_t fill = mp_styles->commit_fill(); + size_t fill_id = mp_styles->commit_fill(); + + if(func.has_border()) + { + const cell_prop_attr_parser::border_map_t& border_map = func.get_border_attrib(); + for (cell_prop_attr_parser::border_map_t::const_iterator itr = border_map.begin(); itr != border_map.end(); ++itr) + { + mp_styles->set_border_color(itr->first , 0, itr->second.red, itr->second.green, itr->second.blue); + mp_styles->set_border_style(itr->first , itr->second.border_style); + mp_styles->set_border_width(itr->first , itr->second.border_width); + + } + + } + + size_t border_id = mp_styles->commit_border(); switch (m_current_style->family) { case style_family_table_cell: { odf_style::cell* data = m_current_style->cell_data; - data->fill = fill; + data->fill = fill_id; + data->border=border_id; } + break; + default: ; } diff --git a/src/liborcus/odf_styles_context_test.cpp b/src/liborcus/odf_styles_context_test.cpp index 7aa5bfe7c1b82b5f529d58ca3f30cc5d200ae1c6..b4277fe8f46d90a9df2b1cf481ab9fffccae3dd5 100644 --- a/src/liborcus/odf_styles_context_test.cpp +++ b/src/liborcus/odf_styles_context_test.cpp @@ -7,6 +7,8 @@ #include #include +#include +#include namespace { @@ -34,13 +36,16 @@ int main() orcus::spreadsheet::import_styles styles(string_pool); orcus::import_ods::read_styles(content.c_str(), content.size(), &styles); - - const orcus::spreadsheet::cell_style_t* style = find_cell_style_by_name("Note", &styles); +/* Test for Cell Fill + ===================================================== +*/ + const orcus::spreadsheet::cell_style_t* style = find_cell_style_by_name("Name1", &styles); assert(style->parent_name == "Text"); size_t xf = style->xf; std::cerr << std::hex << (int)xf; const orcus::spreadsheet::cell_format_t* cell_format = styles.get_cell_style_format(xf); assert(cell_format); + size_t fill = cell_format->fill; std::cerr << std::hex << (int)fill; const orcus::spreadsheet::fill_t* cell_fill = styles.get_fill(fill); @@ -49,5 +54,63 @@ int main() assert(cell_fill->bg_color.red == 0xfe); assert(cell_fill->bg_color.green == 0xff); assert(cell_fill->bg_color.blue == 0xcc); + +/* Test for Border Styles + ===================================================== +*/ + assert(styles.get_border_count()==5); + + /* Test that border style applies to all the sides when not specified */ + style = find_cell_style_by_name("Name1", &styles); + xf = style->xf; + cell_format = styles.get_cell_style_format(xf); + size_t border = cell_format->border; + assert(cell_format); + + const orcus::spreadsheet::border_t* cell_border = styles.get_border(border); + assert(cell_border->top.style == orcus::spreadsheet::border_style_t::thick); + assert(cell_border->bottom.style == orcus::spreadsheet::border_style_t::thick); + assert(cell_border->left.style == orcus::spreadsheet::border_style_t::thick); + assert(cell_border->right.style == orcus::spreadsheet::border_style_t::thick); + assert(cell_border->top.border_color.red == 0xff); + assert(cell_border->bottom.border_color.green == 0xcc); + assert(cell_border->left.border_color.blue == 0x12); + assert(cell_border->right.border_width.value == 0.06); + assert(cell_border->top.border_width.value == 0.06); + + /*Test that border applies to only specified sides*/ + style = find_cell_style_by_name("Name2", &styles); + xf = style->xf; + cell_format = styles.get_cell_style_format(xf); + border = cell_format->border; + assert(cell_format); + + cell_border = styles.get_border(border); + assert(cell_border->top.style == orcus::spreadsheet::border_style_t::dashed); + assert(cell_border->bottom.style == orcus::spreadsheet::border_style_t::thin); + assert(cell_border->left.style == orcus::spreadsheet::border_style_t::none); + assert(cell_border->right.style == orcus::spreadsheet::border_style_t::thin); + assert(cell_border->top.border_color.red == 0xff); + assert(cell_border->bottom.border_color.green == 0xee); + assert(cell_border->left.border_color.blue == 0x11); + assert(cell_border->right.border_width.value == 0.22); + assert(cell_border->bottom.border_width.value == 1.74); + + //TODO : These border styles dont work :- solid,dash_dot,dash_dot_dot ...and some others + + /*Test that border applies to the diagonal*/ + style = find_cell_style_by_name("Name3", &styles); + xf = style->xf; + cell_format = styles.get_cell_style_format(xf); + border = cell_format->border; + assert(cell_format); + + cell_border = styles.get_border(border); + assert(cell_border->diagonal_bl_tr.style == orcus::spreadsheet::border_style_t::thick); + assert(cell_border->diagonal_tl_br.style == orcus::spreadsheet::border_style_t::thin); + assert(cell_border->diagonal_bl_tr.border_color.red == 0xff); + assert(cell_border->diagonal_tl_br.border_color.green == 0x00); + assert(cell_border->diagonal_tl_br.border_width.value == 0.74); + return 0; } diff --git a/src/spreadsheet/styles.cpp b/src/spreadsheet/styles.cpp index 699dbcc410c22dd211163990899431f54019e79b..6639d7adc6057503fc73df8e868a077d151d2ff5 100644 --- a/src/spreadsheet/styles.cpp +++ b/src/spreadsheet/styles.cpp @@ -218,6 +218,12 @@ border_attrs_t* get_border_attrs(border_t& cur_border, border_direction_t dir) case border_direction_t::diagonal: p = &cur_border.diagonal; break; + case border_direction_t::diagonal_bl_tr: + p = &cur_border.diagonal_bl_tr; + break; + case border_direction_t::diagonal_tl_br: + p = &cur_border.diagonal_tl_br; + break; default: ; } @@ -252,6 +258,13 @@ void import_styles::set_border_color( p->border_color = color_t(alpha, red, green, blue); } +void import_styles::set_border_width(border_direction_t dir , length_t width) +{ + border_attrs_t* p = get_border_attrs(m_cur_border ,dir); + if(p) + p->border_width = width; +} + size_t import_styles::commit_border() { m_borders.push_back(m_cur_border); diff --git a/test/ods/styles/cell-styles.xml b/test/ods/styles/cell-styles.xml index 6ccf9baaec44999b2d77fd998f706a68b7790467..a948157c4003cd453c842da9b9bcf8b00d86eab6 100644 --- a/test/ods/styles/cell-styles.xml +++ b/test/ods/styles/cell-styles.xml @@ -1,6 +1,16 @@ - - + + + + + + + + + + + +