From 1eb4acf7085dfd95379fcf61fe86aba2a454bc37 Mon Sep 17 00:00:00 2001 From: ElenaSubbotina Date: Wed, 8 Jun 2016 16:42:37 +0300 Subject: [PATCH] =?UTF-8?q?OdfFormatReader=20-=20=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D0=B0=D1=82=D0=B0=D0=BC=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20(=D1=83?= =?UTF-8?q?=D1=81=D0=BB=D0=BE=D0=B2=D0=BD=D0=BE=D0=B5=20=D1=84=D0=BE=D1=80?= =?UTF-8?q?=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../formulasconvert/formulasconvert.h | 4 +- .../formulasconvert/formulasconvert_odf.cpp | 753 +++++++++--------- .../formulasconvert/formulasconvert_oox.cpp | 1 + .../src/docx/xlsx_conditionalFormatting.cpp | 114 ++- ASCOfficeOdfFile/src/docx/xlsx_dxfs.cpp | 2 +- .../src/odf/datatypes/calcext_type.cpp | 3 +- .../src/odf/datatypes/calcext_type.h | 3 +- .../src/odf/datatypes/iconset_type.cpp | 33 +- 8 files changed, 493 insertions(+), 420 deletions(-) diff --git a/ASCOfficeOdfFile/formulasconvert/formulasconvert.h b/ASCOfficeOdfFile/formulasconvert/formulasconvert.h index edab9eb06d..83ebfe3292 100644 --- a/ASCOfficeOdfFile/formulasconvert/formulasconvert.h +++ b/ASCOfficeOdfFile/formulasconvert/formulasconvert.h @@ -19,10 +19,10 @@ public: std::wstring convert(std::wstring const & expr); // $1.$A$1 -> 1!$A$1 - std::wstring convert_named_ref(std::wstring const & expr); + std::wstring convert_named_ref(std::wstring const & expr, bool withTableName = true); //a-la convert without check formula - std::wstring convert_named_expr(std::wstring const & expr); + std::wstring convert_named_expr(std::wstring const & expr, bool withTableName = true); //Sheet2.C3:Sheet2.C19 -> Sheet2!C3:C19 std::wstring convert_chart_distance(std::wstring const & expr); diff --git a/ASCOfficeOdfFile/formulasconvert/formulasconvert_odf.cpp b/ASCOfficeOdfFile/formulasconvert/formulasconvert_odf.cpp index 67feacebd3..91047e8267 100644 --- a/ASCOfficeOdfFile/formulasconvert/formulasconvert_odf.cpp +++ b/ASCOfficeOdfFile/formulasconvert/formulasconvert_odf.cpp @@ -10,18 +10,26 @@ namespace formulasconvert { class odf2oox_converter::Impl { public: + static bool convert_with_TableName; + std::wstring convert(const std::wstring& expr); std::wstring convert_chart_distance(const std::wstring& expr); - void replace_cells_range(std::wstring& expr); + void replace_cells_range(std::wstring& expr, bool withTableName); bool check_formula(std::wstring& expr); void replace_semicolons(std::wstring& expr); void replace_vertical(std::wstring& expr); void replace_space(std::wstring& expr); - void replace_named_ref(std::wstring & expr); + static std::wstring replace_named_ref_formater(boost::wsmatch const & what); + static std::wstring replace_named_ref_formater1(boost::wsmatch const & what); + static std::wstring replace_cell_range_formater(boost::wsmatch const & what); + + void replace_named_ref(std::wstring & expr, bool w = true); bool find_first_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref); bool find_first_last_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref_first,std::wstring & ref_last); }; + bool odf2oox_converter::Impl::convert_with_TableName = true; + bool odf2oox_converter::Impl::find_first_last_ref(std::wstring const & expr, std::wstring & table,std::wstring & ref_first,std::wstring & ref_last) { std::vector< std::wstring > splitted; @@ -69,7 +77,8 @@ namespace formulasconvert { return false; } - std::wstring replace_cell_range_formater(boost::wsmatch const & what) + + std::wstring odf2oox_converter::Impl::replace_cell_range_formater(boost::wsmatch const & what) { const size_t sz = what.size(); if (sz == 4 && !what[1].matched) @@ -93,7 +102,7 @@ namespace formulasconvert { return L""; } - std::wstring replace_named_ref_formater(boost::wsmatch const & what) + std::wstring odf2oox_converter::Impl::replace_named_ref_formater(boost::wsmatch const & what) { const size_t sz = what.size(); @@ -111,12 +120,37 @@ namespace formulasconvert { const std::wstring c1 = what[2].str(); const std::wstring c2 = what[3].str(); - const std::wstring s = sheet1 + L"!" + c1 + (c2.empty() ? L"" : (L":" + c2) ); - return s; + + if (convert_with_TableName) + { + return (sheet1 + L"!") + c1 + (c2.empty() ? L"" : (L":" + c2) ); + } + else + { + return c1 + (c2.empty() ? L"" : (L":" + c2) ); + } + } + else if (sz == 5 && what[1].matched) + { + std::wstring sheet1 = what[1].str(); + boost::algorithm::replace_all(sheet1, L"$", L""); + + const std::wstring c1 = what[2].str(); + const std::wstring c2 = what[3].str(); //sheet name 2 + const std::wstring c3 = what[4].str(); + + if (convert_with_TableName) + { + return (sheet1 + L"!") + c1 + (c2.empty() ? L"" : (L":" + c3) ); + } + else + { + return c1 + (c3.empty() ? L"" : (L":" + c3) ); + } } return L""; } - std::wstring replace_named_ref_formater1(boost::wsmatch const & what) + std::wstring odf2oox_converter::Impl::replace_named_ref_formater1(boost::wsmatch const & what) { boost::wregex complexRef(L"\\${0,1}([^\\.]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}"); @@ -132,386 +166,367 @@ namespace formulasconvert { } -// заменяем формат адресации ячеек -// [.A1] -> A1 -// [.A1:.B5] -> A1:B5 -// [Sheet2.A1:B5] -> Sheet2!A1:B5 -// [Sheet2.A1] -> Sheet2!A1 -// [$'Sheet2 A'.$B2] -> 'Sheet2 A'!$B2 -void odf2oox_converter::Impl::replace_cells_range(std::wstring& expr) -{ - //boost::wregex simpleRef(L"\\[\\.([a-zA-Z]+\\d+)(?::\\.([a-zA-Z]+\\d+)){0,1}\\]"); - boost::wregex complexRef(L"\\[(?:\\$)?([^\\.]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}\\]"); - /* - [ $ Sheet2 . A1 : . B5 ] - */ - - const std::wstring res = boost::regex_replace( - expr, - complexRef, - &replace_named_ref_formater, - boost::match_default | boost::format_all); - expr = res; -} - - - -void odf2oox_converter::Impl::replace_named_ref(std::wstring & expr) -{ - boost::wregex complexRef(L"\\${0,1}([^\\.]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}"); - - const std::wstring res = boost::regex_replace( - expr, - complexRef, - &replace_named_ref_formater, - boost::match_default | boost::format_all); - expr = res; -} - -// распознаем и заменяем формат формулы -// of:=(Formula) -> (Formula) -bool odf2oox_converter::Impl::check_formula(std::wstring& expr) -{ - boost::match_results res; - if (boost::regex_search(expr, res, boost::wregex(L"(?:[\\w]+:)?=(.+)"), boost::match_default)) - { - expr = res[1].str(); - return true; - } - else - return false; -} - -namespace -{ - -std::wstring replace_semicolons_formater(boost::wsmatch const & what) -{ - if (what[1].matched) - return L","; - else if (what[2].matched) - return what[2].str(); - else if (what[3].matched) - return what[3].str(); - //else if (what[4].matched) - // return what[4].str(); - else - return L""; -} - -} - -// TODO -// заменить точки с запятой во всех вхождениях кроме находящихся в кавычках --*и в фигурных скобках*-- -// TODO: проверить как сохраняются кавычки в строке -void odf2oox_converter::Impl::replace_semicolons(std::wstring& expr) -{ - const std::wstring res = boost::regex_replace( - expr, - //boost::wregex(L"(;)|(?:\".*?\")|(?:'.*?')"), - boost::wregex(L"(;)|(\".*?\")|('.*?')"), - &replace_semicolons_formater, - boost::match_default | boost::format_all); - expr = res; -} - -namespace -{ - -std::wstring replace_vertical_formater(boost::wsmatch const & what) -{ - if (what[1].matched) - { - std::wstring inner = what[1].str(); - boost::algorithm::replace_all(inner, L"|", L";"); - return L"{" + inner + L"}"; - } - else if (what[2].matched) - return what[2].str(); - else if (what[3].matched) - return what[3].str(); -} -std::wstring replace_space_PROBEL(boost::wsmatch const & what) -{ - if (what[1].matched) - { - std::wstring inner = what[1].str(); - boost::algorithm::replace_all(inner, L" ", L"PROBEL"); - return inner; - } - else if (what[2].matched) - return what[2].str(); - else if (what[3].matched) - return what[3].str(); -} -std::wstring replace_point(boost::wsmatch const & what) -{ - if (what[1].matched) - { - std::wstring inner = what[1].str(); - boost::algorithm::replace_all(inner, L".", L"ТОСHKA"); - return inner; - } - else if (what[2].matched) - return what[2].str(); - else if (what[3].matched) - return what[3].str(); -} -std::wstring replace_space_formater(boost::wsmatch const & what) -{ - if (what[1].matched) - { - std::wstring inner = what[1].str(); - boost::algorithm::replace_all(inner, L" ", L","); - return inner; - } - else if (what[2].matched) - return what[2].str(); - else if (what[3].matched) - return what[3].str(); -} -} - -std::wstring forbidden_formulas[] = -{ - L"NULLFORMULA" - /* - L"BETADIST", - L"CEILING", - L"FLOOR", - L"RANK", - L"ROUND", - L"ROUNDDOWN", - L"ROUNDUP", - L"SUBTOTAL", - L"FORMULA", - L"ISREF"*/ -}; - -bool is_forbidden(const std::wstring & formula) -{ - BOOST_FOREACH(const std::wstring & s, forbidden_formulas) - { - if (boost::algorithm::contains(formula, s)) - return true; - } - return false; -} - -// заменить вертикальную черту во всех вхождениях в фигурных скобках, но не внутри строк -void odf2oox_converter::Impl::replace_vertical(std::wstring& expr) -{ - const std::wstring res = boost::regex_replace( - expr, - boost::wregex(L"(?:(?:\\{)([^\\}]*?)(?:\\}))|(\".*?\")|('.*?')"), - &replace_vertical_formater, - boost::match_default | boost::format_all); - expr = res; -} -// заменить пробел во всех вхождениях на запятую -void odf2oox_converter::Impl::replace_space(std::wstring& expr) -{ - const std::wstring res = boost::regex_replace( - expr, - boost::wregex(L"(?:(?:\\{)([^\\}]*?)(?:\\}))|(\".*?\")|('.*?')"), - &replace_space_formater, - boost::match_default | boost::format_all); - expr = res; -} - -std::wstring odf2oox_converter::Impl::convert(const std::wstring& expr) -{ - if (is_forbidden(expr)) - return L"NULLFORMULA()"; - - boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там точек на ТОСHKA - - std::wstring workstr = boost::regex_replace( - expr, - complexRef, - &replace_point, - boost::match_default | boost::format_all); - - boost::algorithm::replace_all(workstr, L" ", L"PROBEL"); - boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); - - check_formula(workstr); - replace_cells_range(workstr); - replace_semicolons(workstr); - replace_vertical(workstr); - - int res_find=0; - if ((res_find = workstr.find(L"CONCATINATE")) > 0) + // заменяем формат адресации ячеек + // [.A1] -> A1 + // [.A1:.B5] -> A1:B5 + // [Sheet2.A1:B5] -> Sheet2!A1:B5 + // [Sheet2.A1] -> Sheet2!A1 + // [$'Sheet2 A'.$B2] -> 'Sheet2 A'!$B2 + void odf2oox_converter::Impl::replace_cells_range(std::wstring& expr, bool withTableName) { - //могут быть частично заданы диапазоны - //todooo + convert_with_TableName = withTableName; + //boost::wregex simpleRef(L"\\[\\.([a-zA-Z]+\\d+)(?::\\.([a-zA-Z]+\\d+)){0,1}\\]"); + boost::wregex complexRef(L"\\[(?:\\$)?([^\\.]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}\\]"); + /* + [ $ Sheet2 . A1 : . B5 ] + */ + const std::wstring res = boost::regex_replace( + expr, + complexRef, + &replace_named_ref_formater, + boost::match_default | boost::format_all); + expr = res; } - boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); - boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); - boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); - return workstr; -} - - -//Sheet2.C3:Sheet2.C19 Sheet2.L29:Sheet2.L36 -//в -//Sheet2!C3:C19,Sheet2!L27:L34 -std::wstring odf2oox_converter::Impl::convert_chart_distance(const std::wstring& expr) -{ - if (is_forbidden(expr)) - return L"NULLFORMULA()"; - - std::wstring workstr = expr; - boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там пробелов на PROBEL - - workstr = boost::regex_replace( - expr, - complexRef, - &replace_space_PROBEL, - boost::match_default | boost::format_all); - - //распарсить по диапазонам - одф-пробел, ик-эль-запятая - - std::vector distance_inp; - std::vector distance_out; - - boost::algorithm::split(distance_inp, workstr, boost::algorithm::is_any_of(L" "), boost::algorithm::token_compress_on); - - BOOST_FOREACH(std::wstring &d,distance_inp) + void odf2oox_converter::Impl::replace_named_ref(std::wstring & expr, bool withTableName) { - std::wstring sheet; - std::vector range; - std::vector cells; - - boost::algorithm::split(range,d, boost::algorithm::is_any_of(L":"), boost::algorithm::token_compress_on); - - BOOST_FOREACH(std::wstring &c,range) - { - const ::std::string::size_type colon = c.find('.'); - cells.push_back(c.substr(colon+1)); - if (sheet.size()<1) - sheet=c.substr(0, colon); - } - std::wstring cells_out; - BOOST_FOREACH(std::wstring &c,cells) - { - cells_out.append(c); - cells_out.append(L":"); - } - int res1 = sheet.find(L"-"); - int res2 = sheet.find(L"'"); + convert_with_TableName = withTableName; - if (res1 >= 0 && !(res2 == 0)) + //boost::wregex complexRef(L"\\${0,1}([^\\.]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}"); + boost::wregex complexRef(L"\\${0,1}([^\\.\\s]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)(?::\\${0,1}([^\\.\\s]+?){0,1}\\.(\\${0,1}[a-zA-Z]+\\${0,1}\\d+)){0,1}"); + + const std::wstring res = boost::regex_replace( + expr, + complexRef, + &replace_named_ref_formater, + boost::match_default | boost::format_all); + expr = res; + } + + // распознаем и заменяем формат формулы + // of:=(Formula) -> (Formula) + bool odf2oox_converter::Impl::check_formula(std::wstring& expr) + { + boost::match_results res; + if (boost::regex_search(expr, res, boost::wregex(L"(?:[\\w]+:)?=(.+)"), boost::match_default)) { - sheet = L"'" + sheet + L"'"; + expr = res[1].str(); + return true; } - - distance_out.push_back(sheet+L"!" + cells_out.substr(0, cells_out.size()-1)); + else + return false; } - std::wstring result; - BOOST_FOREACH(std::wstring &d, distance_out) + + std::wstring replace_semicolons_formater(boost::wsmatch const & what) { - result.append(d); - result.append(L","); + if (what[1].matched) + return L","; + else if (what[2].matched) + return what[2].str(); + else if (what[3].matched) + return what[3].str(); + //else if (what[4].matched) + // return what[4].str(); + else + return L""; } - boost::algorithm::replace_all(result, L"PROBEL", L" "); - - return result.substr(0, result.size()-1);// минус последняя лишняя запятая -} -odf2oox_converter::odf2oox_converter(): impl_(new odf2oox_converter::Impl) -{ -} -odf2oox_converter::~odf2oox_converter() -{ -} - -std::wstring odf2oox_converter::convert(const std::wstring& expr) -{ - return impl_->convert(expr); -} -std::wstring odf2oox_converter::convert_chart_distance(const std::wstring& expr) -{ - return impl_->convert_chart_distance(expr); -} -std::wstring odf2oox_converter::convert_named_ref(const std::wstring& expr) -{ - boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там точек на ТОСHKA - - std::wstring workstr = boost::regex_replace( - expr, - complexRef, - &replace_point, - boost::match_default | boost::format_all); - - boost::algorithm::replace_all(workstr, L" ", L"PROBEL"); - boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); - - impl_->replace_named_ref(workstr); - - boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); - boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); - boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); - return workstr; -} -std::wstring odf2oox_converter::convert_named_expr(const std::wstring& expr) -{ - boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там точек на ТОСHKA - - std::wstring workstr = boost::regex_replace( - expr, - complexRef, - &replace_point, - boost::match_default | boost::format_all); - - boost::algorithm::replace_all(workstr, L" ", L"PROBEL"); - boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); - - impl_->replace_cells_range(workstr); - impl_->replace_semicolons(workstr); - impl_->replace_vertical(workstr); - - int res_find=0; - if ((res_find = workstr.find(L"CONCATINATE")) > 0) + // TODO + // заменить точки с запятой во всех вхождениях кроме находящихся в кавычках --*и в фигурных скобках*-- + // TODO: проверить как сохраняются кавычки в строке + void odf2oox_converter::Impl::replace_semicolons(std::wstring& expr) { - //могут быть частично заданы диапазоны - //todooo - + const std::wstring res = boost::regex_replace( + expr, + //boost::wregex(L"(;)|(?:\".*?\")|(?:'.*?')"), + boost::wregex(L"(;)|(\".*?\")|('.*?')"), + &replace_semicolons_formater, + boost::match_default | boost::format_all); + expr = res; } - boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); - boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); - boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); - return workstr; -} -std::wstring odf2oox_converter::convert_ref(std::wstring const & expr) -{ - std::wstring workstr = L"[" + expr + L"]"; - impl_->replace_cells_range(workstr); - return workstr; -} -std::wstring odf2oox_converter::convert_spacechar(std::wstring expr) -{ - while(true) + std::wstring replace_vertical_formater(boost::wsmatch const & what) { - int pos = expr.find(L"%20"); - if (pos <0)break; - - expr.replace(pos,3,L" "); + if (what[1].matched) + { + std::wstring inner = what[1].str(); + boost::algorithm::replace_all(inner, L"|", L";"); + return L"{" + inner + L"}"; + } + else if (what[2].matched) + return what[2].str(); + else if (what[3].matched) + return what[3].str(); } - return expr; -} -bool odf2oox_converter::find_first_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref) -{ - return impl_->find_first_ref(expr, table, ref); -} -bool odf2oox_converter::find_first_last_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref_first,std::wstring & ref_last) -{ - return impl_->find_first_last_ref(expr, table, ref_first,ref_last); -} + std::wstring replace_point_space(boost::wsmatch const & what) + { + if (what[1].matched) + { + std::wstring inner = what[1].str(); + boost::algorithm::replace_all(inner, L".", L"ТОСHKA"); + boost::algorithm::replace_all(inner, L" ", L"PROBEL"); + return inner; + } + else if (what[2].matched) + return what[2].str(); + else if (what[3].matched) + return what[3].str(); + } + std::wstring replace_space_formater(boost::wsmatch const & what) + { + if (what[1].matched) + { + std::wstring inner = what[1].str(); + boost::algorithm::replace_all(inner, L" ", L","); + return inner; + } + else if (what[2].matched) + return what[2].str(); + else if (what[3].matched) + return what[3].str(); + } + + + std::wstring forbidden_formulas[] = + { + L"NULLFORMULA" + /* + L"BETADIST", + L"CEILING", + L"FLOOR", + L"RANK", + L"ROUND", + L"ROUNDDOWN", + L"ROUNDUP", + L"SUBTOTAL", + L"FORMULA", + L"ISREF"*/ + }; + + bool is_forbidden(const std::wstring & formula) + { + BOOST_FOREACH(const std::wstring & s, forbidden_formulas) + { + if (boost::algorithm::contains(formula, s)) + return true; + } + return false; + } + + // заменить вертикальную черту во всех вхождениях в фигурных скобках, но не внутри строк + void odf2oox_converter::Impl::replace_vertical(std::wstring& expr) + { + const std::wstring res = boost::regex_replace( + expr, + boost::wregex(L"(?:(?:\\{)([^\\}]*?)(?:\\}))|(\".*?\")|('.*?')"), + &replace_vertical_formater, + boost::match_default | boost::format_all); + expr = res; + } + // заменить пробел во всех вхождениях на запятую + void odf2oox_converter::Impl::replace_space(std::wstring& expr) + { + const std::wstring res = boost::regex_replace( + expr, + boost::wregex(L"(?:(?:\\{)([^\\}]*?)(?:\\}))|(\".*?\")|('.*?')"), + &replace_space_formater, + boost::match_default | boost::format_all); + expr = res; + } + + std::wstring odf2oox_converter::Impl::convert(const std::wstring& expr) + { + if (is_forbidden(expr)) + return L"NULLFORMULA()"; + + boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')"); + + std::wstring workstr = boost::regex_replace( + expr, + complexRef, + &replace_point_space, + boost::match_default | boost::format_all); + + boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); + + check_formula(workstr); + replace_cells_range(workstr, true); + replace_semicolons(workstr); + replace_vertical(workstr); + + int res_find=0; + if ((res_find = workstr.find(L"CONCATINATE")) > 0) + { + //могут быть частично заданы диапазоны + //todooo + + } + boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); + boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); + boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); + return workstr; + } + + + //Sheet2.C3:Sheet2.C19 Sheet2.L29:Sheet2.L36 + //в + //Sheet2!C3:C19,Sheet2!L27:L34 + std::wstring odf2oox_converter::Impl::convert_chart_distance(const std::wstring& expr) + { + if (is_forbidden(expr)) + return L"NULLFORMULA()"; + + std::wstring workstr = expr; + boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там + + workstr = boost::regex_replace( + expr, + complexRef, + &replace_point_space, + boost::match_default | boost::format_all); + + //распарсить по диапазонам - одф-пробел, ик-эль-запятая + + std::vector distance_inp; + std::vector distance_out; + + boost::algorithm::split(distance_inp, workstr, boost::algorithm::is_any_of(L" "), boost::algorithm::token_compress_on); + + BOOST_FOREACH(std::wstring &d,distance_inp) + { + std::wstring sheet; + std::vector range; + std::vector cells; + + boost::algorithm::split(range,d, boost::algorithm::is_any_of(L":"), boost::algorithm::token_compress_on); + + BOOST_FOREACH(std::wstring &c,range) + { + const ::std::string::size_type colon = c.find('.'); + cells.push_back(c.substr(colon+1)); + if (sheet.size()<1) + sheet=c.substr(0, colon); + } + std::wstring cells_out; + BOOST_FOREACH(std::wstring &c,cells) + { + cells_out.append(c); + cells_out.append(L":"); + } + int res1 = sheet.find(L"-"); + int res2 = sheet.find(L"'"); + + if (res1 >= 0 && !(res2 == 0)) + { + sheet = L"'" + sheet + L"'"; + } + + distance_out.push_back(sheet+L"!" + cells_out.substr(0, cells_out.size()-1)); + } + std::wstring result; + + BOOST_FOREACH(std::wstring &d, distance_out) + { + result.append(d); + result.append(L","); + } + boost::algorithm::replace_all(result, L"PROBEL" , L" "); + boost::algorithm::replace_all(result, L"TOCHKA" , L"."); + + return result.substr(0, result.size()-1);// минус последняя лишняя запятая + } + odf2oox_converter::odf2oox_converter(): impl_(new odf2oox_converter::Impl) + { + } + + odf2oox_converter::~odf2oox_converter() + { + } + + std::wstring odf2oox_converter::convert(const std::wstring& expr) + { + return impl_->convert(expr); + } + std::wstring odf2oox_converter::convert_chart_distance(const std::wstring& expr) + { + return impl_->convert_chart_distance(expr); + } + std::wstring odf2oox_converter::convert_named_ref(const std::wstring& expr, bool withTableName) + { + boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там + + std::wstring workstr = boost::regex_replace( + expr, + complexRef, + &replace_point_space, + boost::match_default | boost::format_all); + + boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); + + impl_->replace_named_ref(workstr, withTableName); + + boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); + boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); + boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); + return workstr; + } + std::wstring odf2oox_converter::convert_named_expr(const std::wstring& expr, bool withTableName) + { + boost::wregex complexRef(L"('(?!\\s\\'){0,1}.*?')");// поиск того что в апострофах и замена там + + std::wstring workstr = boost::regex_replace( + expr, + complexRef, + &replace_point_space, + boost::match_default | boost::format_all); + + boost::algorithm::replace_all(workstr, L"'", L"APOSTROF"); + + impl_->replace_cells_range(workstr, withTableName); + impl_->replace_semicolons(workstr); + impl_->replace_vertical(workstr); + + int res_find=0; + if ((res_find = workstr.find(L"CONCATINATE")) > 0) + { + //могут быть частично заданы диапазоны + //todooo + + } + boost::algorithm::replace_all(workstr, L"PROBEL" , L" "); + boost::algorithm::replace_all(workstr, L"APOSTROF" , L"'"); + boost::algorithm::replace_all(workstr, L"TOCHKA" , L"."); + return workstr; + } + + std::wstring odf2oox_converter::convert_ref(std::wstring const & expr) + { + std::wstring workstr = L"[" + expr + L"]"; + impl_->replace_cells_range(workstr, true); + return workstr; + } + std::wstring odf2oox_converter::convert_spacechar(std::wstring expr) + { + while(true) + { + int pos = expr.find(L"%20"); + if (pos <0)break; + + expr.replace(pos,3,L" "); + } + return expr; + } + + bool odf2oox_converter::find_first_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref) + { + return impl_->find_first_ref(expr, table, ref); + } + bool odf2oox_converter::find_first_last_ref(std::wstring const & expr, std::wstring & table, std::wstring & ref_first,std::wstring & ref_last) + { + return impl_->find_first_last_ref(expr, table, ref_first, ref_last); + } } } diff --git a/ASCOfficeOdfFile/formulasconvert/formulasconvert_oox.cpp b/ASCOfficeOdfFile/formulasconvert/formulasconvert_oox.cpp index ea0c291954..715b1660cc 100644 --- a/ASCOfficeOdfFile/formulasconvert/formulasconvert_oox.cpp +++ b/ASCOfficeOdfFile/formulasconvert/formulasconvert_oox.cpp @@ -26,6 +26,7 @@ public: static std::wstring replace_cells_range_formater2(boost::wsmatch const & what); static std::wstring replace_arguments(boost::wsmatch const & what); static std::wstring convert_scobci(boost::wsmatch const & what); + std::wstring replace_arguments1(std::wstring & workstr); void replace_named_ref(std::wstring & expr); diff --git a/ASCOfficeOdfFile/src/docx/xlsx_conditionalFormatting.cpp b/ASCOfficeOdfFile/src/docx/xlsx_conditionalFormatting.cpp index a266143229..3bfd667c79 100644 --- a/ASCOfficeOdfFile/src/docx/xlsx_conditionalFormatting.cpp +++ b/ASCOfficeOdfFile/src/docx/xlsx_conditionalFormatting.cpp @@ -30,9 +30,12 @@ namespace oox { case 3: CP_XML_ATTR(L"type", L"min"); break; case 4: CP_XML_ATTR(L"type", L"max"); break; //todooo ext - autoMax case 5: CP_XML_ATTR(L"type", L"min"); break; + case 6: CP_XML_ATTR(L"type", L"formula"); break; } - if (val) + if (val) + { CP_XML_ATTR(L"val", *val); + } } } } @@ -47,6 +50,7 @@ namespace oox { _CP_OPT(std::wstring) operator_; //expr _CP_OPT(std::wstring) formula; + _CP_OPT(std::wstring) formula_type; //color scale icon set data_bar std::vector<_cfvo> cfvo; //color scale data_bar(1 element) @@ -81,13 +85,16 @@ public: for (int i = 0 ; i < conditionalFormattings_.size(); i++) { conditionalFormatting & c = conditionalFormattings_[i]; - CP_XML_NODE(L"conditionalFormatting") + + if (c.rules.size() < 1) continue; + + CP_XML_NODE(L"conditionalFormatting") { CP_XML_ATTR(L"sqref", c.ref); for (int j = 0 ; j < c.rules.size(); j++) { - if (c.rules[j].type < 1 || c.rules[j].type > 4) continue; + if (c.rules[j].type < 1 || c.rules[j].type > 5) continue; CP_XML_NODE(L"cfRule") { @@ -105,7 +112,7 @@ public: //CP_XML_ATTR(L"aboveAverage" , 0); if (c.rules[j].type == 1) { - CP_XML_ATTR(L"type", L"expression"); + CP_XML_ATTR(L"type", *c.rules[j].formula_type); if (c.rules[j].formula) { CP_XML_NODE(L"formula") @@ -195,26 +202,7 @@ void xlsx_conditionalFormatting_context::add(std::wstring ref) formulasconvert::odf2oox_converter converter; impl_->conditionalFormattings_.push_back(conditionalFormatting()); - ref = converter.convert_named_ref(ref); - -//'Fitness Plan'!N20:'Fitness Plan'!P22; K25 -> N20:P22 - int pos_cells = ref.find(L":"); - std::wstring ref2; - if (pos_cells >0) - { - ref2 = ref.substr(pos_cells + 1); - ref = ref.substr(0, pos_cells); - pos_cells = ref2.find(L"!"); - if (pos_cells > 0) - ref2 = ref2.substr(pos_cells + 1); - } - pos_cells = ref.find(L"!"); - if (pos_cells > 0) - ref = ref.substr(pos_cells + 1); - - if (!ref2.empty()) ref += L":" + ref2; - - impl_->conditionalFormattings_.back().ref = ref; + impl_->conditionalFormattings_.back().ref = converter.convert_named_ref(ref, false); } void xlsx_conditionalFormatting_context::add_rule(int type) @@ -225,13 +213,73 @@ void xlsx_conditionalFormatting_context::add_rule(int type) } void xlsx_conditionalFormatting_context::set_formula(std::wstring f) { - int pos = f.find(L"formula-is("); - if ( pos >= 0 ) + int pos = -1; + std::wstring val; + if ( 0 <= (pos = f.find(L"formula-is("))) { - f = f.substr(11, f.size() - 12); + impl_->conditionalFormattings_.back().rules.back().formula_type = L"expression"; + val = f.substr(11, f.size() - 12); } + else if (0 <= (pos = f.find(L"is-between("))) + { + } + else if (0 <= (pos = f.find(L"is-time("))) + { + } + else + { + impl_->conditionalFormattings_.back().rules.back().formula_type = L"cellIs"; + + if (0 <= (pos = f.find(L"!empty"))) + { + } + else if (0 <= (pos = f.find(L"empty"))) + { + } + else if (0 <= (pos = f.find(L"bottom"))) + { + } + else if (0 <= (pos = f.find(L"top"))) + { + } + else if (0 <= (pos = f.find(L"!="))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"notEqual"; + val = f.substr(2); + } + else if (0 <= (pos = f.find(L"<="))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"lessThanOrEqual"; + val = f.substr(2); + } + else if (0 <= (pos = f.find(L">="))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"greaterThanOrEqual"; + val = f.substr(2); + } + else if (0 <= (pos = f.find(L"="))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"equal"; + val = f.substr(1); + } + else if (0 <= (pos = f.find(L"<"))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"lessThan"; + val = f.substr(1); + } + else if (0 <= (pos = f.find(L">"))) + { + impl_->conditionalFormattings_.back().rules.back().operator_ = L"greaterThan"; + val = f.substr(1); + } + else + { + val = f; + } + } + formulasconvert::odf2oox_converter converter; - impl_->conditionalFormattings_.back().rules.back().formula = converter.convert_named_expr(f); + impl_->conditionalFormattings_.back().rules.back().formula = converter.convert_named_expr(val); } void xlsx_conditionalFormatting_context::set_dataBar(_CP_OPT(int) min, _CP_OPT(int) max) { @@ -246,7 +294,15 @@ void xlsx_conditionalFormatting_context::add_sfv(int type, std::wstring value) { _cfvo cfvo; cfvo.type = type; - if (!value.empty()) cfvo.val = value; + + if ( type == 6) + { + set_formula(value); + cfvo.val =impl_->conditionalFormattings_.back().rules.back().formula; + + impl_->conditionalFormattings_.back().rules.back().formula.reset(); + } + else if (!value.empty()) cfvo.val = value; impl_->conditionalFormattings_.back().rules.back().cfvo.push_back(cfvo); } diff --git a/ASCOfficeOdfFile/src/docx/xlsx_dxfs.cpp b/ASCOfficeOdfFile/src/docx/xlsx_dxfs.cpp index ad1c35ce41..9dfcf2b07c 100644 --- a/ASCOfficeOdfFile/src/docx/xlsx_dxfs.cpp +++ b/ASCOfficeOdfFile/src/docx/xlsx_dxfs.cpp @@ -63,8 +63,8 @@ void xlsx_dxfs::serialize(std::wostream & _Wostream) const { CP_XML_NODE(L"dxf") { - xlsx_serialize(CP_XML_STREAM(), impl_->dxf_array[i].fill); xlsx_serialize(CP_XML_STREAM(), impl_->dxf_array[i].font); + xlsx_serialize(CP_XML_STREAM(), impl_->dxf_array[i].fill); } } } diff --git a/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.cpp b/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.cpp index eb5b5b5c7f..bcaa49cde8 100644 --- a/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.cpp +++ b/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.cpp @@ -51,9 +51,10 @@ calcext_type calcext_type::parse(const std::wstring & Str) return calcext_type( Maximum ); else if (tmp == L"minimum") return calcext_type( Minimum ); + else if (tmp == L"formula") + return calcext_type( Formula ); else { - BOOST_THROW_EXCEPTION( errors::invalid_attribute() ); return calcext_type( Number ); } } diff --git a/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.h b/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.h index bbf6e40fef..e960915300 100644 --- a/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.h +++ b/ASCOfficeOdfFile/src/odf/datatypes/calcext_type.h @@ -17,7 +17,8 @@ public: Maximum, Minimum, AutoMaximum, - AutoMinimum + AutoMinimum, + Formula }; calcext_type() {} diff --git a/ASCOfficeOdfFile/src/odf/datatypes/iconset_type.cpp b/ASCOfficeOdfFile/src/odf/datatypes/iconset_type.cpp index 8450ce0a13..23be1eef1b 100644 --- a/ASCOfficeOdfFile/src/odf/datatypes/iconset_type.cpp +++ b/ASCOfficeOdfFile/src/odf/datatypes/iconset_type.cpp @@ -72,43 +72,42 @@ iconset_type iconset_type::parse(const std::wstring & Str) std::wstring tmp = Str; boost::algorithm::to_lower(tmp); - if (tmp == L"3Arrows") + if (tmp == L"3arrows") return iconset_type( Arrows3 ); - else if (tmp == L"3ArrowsGray") + else if (tmp == L"3arrowsgray") return iconset_type( Arrows3Gray ); - else if (tmp == L"3Flags") + else if (tmp == L"3flags") return iconset_type( Flags3 ); - else if (tmp == L"3Signs") + else if (tmp == L"3signs") return iconset_type( Signs3 ); - else if (tmp == L"3Symbols") + else if (tmp == L"3symbols") return iconset_type( Symbols3 ); - else if (tmp == L"3Symbols2") + else if (tmp == L"3symbols2") return iconset_type( Symbols3_2 ); - else if (tmp == L"3TrafficLights1") + else if (tmp == L"3trafficlights1") return iconset_type( Traffic3Lights1 ); - else if (tmp == L"3TrafficLights2") + else if (tmp == L"3trafficlights2") return iconset_type( Traffic3Lights2 ); - else if (tmp == L"4Arrows") + else if (tmp == L"4arrows") return iconset_type( Arrows4 ); - else if (tmp == L"4ArrowsGray") + else if (tmp == L"4arrowsgray") return iconset_type( Arrows4Gray ); else if (tmp == L"4Rating") return iconset_type( Rating4 ); - else if (tmp == L"4RedToBlack") + else if (tmp == L"4redtoblack") return iconset_type( RedToBlack4 ); - else if (tmp == L"4TrafficLights") + else if (tmp == L"4trafficlights") return iconset_type( Traffic4Lights ); - else if (tmp == L"5Arrows") + else if (tmp == L"5arrows") return iconset_type( Arrows5 ); - else if (tmp == L"5ArrowsGray") + else if (tmp == L"5arrowsgray") return iconset_type( Arrows5Gray ); - else if (tmp == L"5Quarters") + else if (tmp == L"5quarters") return iconset_type( Quarters5 ); - else if (tmp == L"5Rating") + else if (tmp == L"5rating") return iconset_type( Rating5 ); else { - BOOST_THROW_EXCEPTION( errors::invalid_attribute() ); return iconset_type( Arrows3 ); } }