/* * (c) Copyright Ascensio System SIA 2010-2023 * * This program is a free software product. You can redistribute it and/or * modify it under the terms of the GNU Affero General Public License (AGPL) * version 3 as published by the Free Software Foundation. In accordance with * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect * that Ascensio System SIA expressly excludes the warranty of non-infringement * of any third-party rights. * * This program is distributed WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html * * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish * street, Riga, Latvia, EU, LV-1050. * * The interactive user interfaces in modified source and object code versions * of the Program must display Appropriate Legal Notices, as required under * Section 5 of the GNU AGPL version 3. * * Pursuant to Section 7(b) of the License you must retain the original Product * logo when distributing the program. Pursuant to Section 7(e) we decline to * grant you any rights under trademark law for use of our trademarks. * * All the Product's GUI elements, including illustrations and icon sets, as * well as technical writing content are licensed under the terms of the * Creative Commons Attribution-ShareAlike 4.0 International. See the License * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode * */ #include #include #include "../Format/odf_document.h" #include "../Format/odfcontext.h" #include "../Format/draw_common.h" #include "../Format/calcs_styles.h" #include "../../DataTypes/borderstyle.h" #include "../../Common/logging.h" #include "pptx_conversion_context.h" namespace cpdoccore { namespace oox { /**/ pptx_table_state::pptx_table_state(pptx_conversion_context & Context, const std::wstring & StyleName) : context_(Context), table_style_(StyleName), current_table_column_(-1), columns_spanned_num_(0), rows_(0), current_row_(0), total_columns_(0) { } void pptx_table_state::start_column(unsigned int repeated, const std::wstring & defaultCellStyleName) { columns_.push_back(repeated); for (unsigned int i = 0; i < repeated; ++i) columnsDefaultCellStyleName_.push_back(defaultCellStyleName); } std::wstring pptx_table_state::get_default_cell_style_col(unsigned int column) { return columnsDefaultCellStyleName_.at(column); } std::wstring pptx_table_state::get_default_cell_style_row() { return default_row_cell_style_name_; } void pptx_table_state::set_default_cell_style_row(const std::wstring& style_name) { default_row_cell_style_name_ = style_name; } void pptx_table_state::set_default_cell_style_col(unsigned int column, const std::wstring style_name) { if (column >= columnsDefaultCellStyleName_.size()) return; columnsDefaultCellStyleName_[column] = style_name; } void pptx_table_state::start_row(const std::wstring & StyleName, const std::wstring & defaultCellStyleName) { current_table_column_ = -1; columns_spanned_style_ = L""; table_row_style_stack_.push_back(StyleName); default_row_cell_style_name_ = defaultCellStyleName; current_row_++; } void pptx_table_state::end_row() { table_row_style_stack_.pop_back(); default_row_cell_style_name_ = L""; } std::wstring pptx_table_state::current_row_style() const { if (table_row_style_stack_.size()) return table_row_style_stack_.back(); else return L""; } void pptx_table_state::start_cell() { current_table_column_++; if (current_table_column_ >= (int)(rows_spanned_.size())) rows_spanned_.push_back(table_row_spanned()); } void pptx_table_state::end_cell() { } bool pptx_table_state::start_covered_cell(pptx_conversion_context & Context) { std::wostream & _Wostream = context_.get_table_context().tableData(); current_table_column_++; // обновляем вектор, в котором хранятся информация об объединении строк // добавляем в него новый столбец if (current_table_column_ >= (int)(rows_spanned_.size())) rows_spanned_.push_back(table_row_spanned()); _Wostream << L" 0) { _Wostream << L" vMerge=\"1\""; if (rows_spanned_[current_table_column_].column_spanned() > 0) _Wostream << L" gridSpan=\"" << rows_spanned_[current_table_column_].column_spanned() + 1 << "\""; _Wostream << L">"; } else { _Wostream << L" hMerge=\"1\">"; } odf_reader::style_instance* inst = context_.root()->odf_context().styleContainer().style_by_name( rows_spanned_[current_table_column_].style(), odf_types::style_family::TableCell, false); // использовали текущую ячейку, уменьшаем счетчики оставшихся объединенных ячеек // для столбцов и строк if (columns_spanned_num_ > 0) columns_spanned_num_--; if (rows_spanned_[current_table_column_].num() > 0) rows_spanned_[current_table_column_].decrease(); return true; } void pptx_table_state::end_covered_cell() { std::wostream & _Wostream = context_.get_table_context().tableData(); std::vector style_instances; std::wstring style_name; odf_reader::style_instance* style_inst = context_.root()->odf_context().styleContainer().style_default_by_type(odf_types::style_family::TableCell); if (style_inst) style_instances.push_back(style_inst); if (!default_cell_style_name_.empty())//template { style_inst = context_.root()->odf_context().styleContainer().style_by_name(default_cell_style_name_, odf_types::style_family::TableCell, false); if (style_inst) style_instances.push_back(style_inst); } if (!default_row_cell_style_name_.empty()) { style_inst = context_.root()->odf_context().styleContainer().style_by_name(default_row_cell_style_name_, odf_types::style_family::TableCell, false); if (style_inst) style_instances.push_back(style_inst); } oox::oox_serialize_tcPr(_Wostream, style_instances, context_); // закрываем открытую ячейку _Wostream << L""; } int pptx_table_state::current_column() const { return current_table_column_; } void pptx_table_state::set_columns_spanned(unsigned int Val) { if ( current_columns_spaned() > 0 ) { } columns_spanned_num_ = Val; } unsigned int pptx_table_state::current_columns_spaned() const { return columns_spanned_num_; } void pptx_table_state::set_rows_spanned(unsigned int Column, unsigned int Val, unsigned int ColumnsSpanned, const std::wstring & Style) { if (rows_spanned_.size() <= Column) { _CP_LOG << L"[warning] set_rows_spanned error\n"; } else { rows_spanned_[Column].num(Val); rows_spanned_[Column].set_style(Style); rows_spanned_[Column].column_spanned(ColumnsSpanned); } } unsigned int pptx_table_state::current_rows_spanned(unsigned int Column) const { if (rows_spanned_.size() <= Column) { _CP_LOG << L"[warning] current_rows_spanned error\n"; return 0; } else { return rows_spanned_[Column].num(); } } void pptx_table_state::set_rows(int rows) { rows_ = rows; } int pptx_table_state::get_rows() const { return rows_; } int pptx_table_state::get_current_row() const { return current_row_; } void pptx_table_state::set_columns(int cols) { total_columns_ = cols; } int pptx_table_state::get_columns() const { return total_columns_; } void pptx_table_state::set_template_row_style_name(const std::wstring style_name) { template_row_style_name_ = style_name; } std::wstring pptx_table_state::get_template_row_style_name() const { return template_row_style_name_; } struct pptx_border_edge { bool present = false; bool none = false; std::wstring color; int width = 0; std::wstring cmpd; std::wstring prstDash; }; void convert_border_style(const odf_types::border_style& borderStyle, pptx_border_edge & border) { border.cmpd = L"sng"; border.prstDash = L"solid"; if (borderStyle.initialized()) { border.present = true; if (borderStyle.is_none()) border.none = true; switch(borderStyle.get_style()) { case odf_types::border_style::none: border.none = true; break; case odf_types::border_style::double_: border.cmpd = L"dbl"; break; case odf_types::border_style::dotted: border.prstDash = L"dot"; break; case odf_types::border_style::dash: border.prstDash = L"dash"; break; case odf_types::border_style::long_dash: border.prstDash = L"lgDash"; break; case odf_types::border_style::dot_dash: border.prstDash = L"dashDot"; break; case odf_types::border_style::dot_dot_dash: border.prstDash = L"lgDashDotDot"; break; } } } //dbl (Double Lines) Double lines of equal width //sng (Single Line) Single line: one normal width //thickThin (Thick Thin Double Lines) Double lines: one thick, one thin //thinThick (Thin Thick Double Lines) Double lines: one thin, one thick //tri (Thin Thick Thin Triple Lines) Three lines: thin, thick, thin void process_border(pptx_border_edge & borderEdge, _CP_OPT(odf_types::border_style) & borderStyle) { borderEdge.present = true; if (borderStyle) { borderEdge.color = borderStyle->get_color().get_hex_value(); borderEdge.width = boost::lexical_cast(borderStyle->get_length().get_value_unit(odf_types::length::emu)); convert_border_style(*borderStyle, borderEdge); } else { borderEdge.none = true; } } void oox_serialize_border(std::wostream & strm, std::wstring Node, pptx_border_edge & content) { if (content.present == false) return; CP_XML_WRITER(strm) { CP_XML_NODE(Node) { if (content.none) { CP_XML_NODE(L"a:noFill") {} } else { CP_XML_ATTR(L"w", content.width); //CP_XML_ATTR(L"cap", L"flat"); CP_XML_ATTR(L"cmpd", content.cmpd); //CP_XML_ATTR(L"algn", L"ctr"); CP_XML_NODE(L"a:solidFill") { _CP_OPT(double) opacity; oox_serialize_srgb(CP_XML_STREAM(), content.color, opacity); } CP_XML_NODE(L"a:prstDash") { CP_XML_ATTR(L"val", content.prstDash); } } } } } void oox_serialize_tcPr(std::wostream & strm, std::vector & instances, oox::pptx_conversion_context & Context) { CP_XML_WRITER(strm) { CP_XML_NODE(L"a:tcPr") { if (instances.size() > 0) { odf_reader::style_table_cell_properties_attlist style_cell_attlist = odf_reader::calc_table_cell_properties(instances); odf_reader::graphic_format_properties_ptr graphic_props = odf_reader::calc_graphic_properties_content(instances); if (style_cell_attlist.style_vertical_align_ || (graphic_props && graphic_props->draw_textarea_vertical_align_)) { odf_types::vertical_align::type algn = style_cell_attlist.style_vertical_align_ ? style_cell_attlist.style_vertical_align_->get_type() : graphic_props->draw_textarea_vertical_align_->get_type(); std::wstring vAlign; switch(algn) { case odf_types::vertical_align::Baseline: case odf_types::vertical_align::Top: vAlign = L"t"; break; case odf_types::vertical_align::Middle: vAlign = L"ctr"; break; case odf_types::vertical_align::Bottom: vAlign = L"b"; break; case odf_types::vertical_align::Auto: break; } if (false == vAlign.empty()) CP_XML_ATTR(L"anchor", vAlign ); } double padding_common = -1; if (style_cell_attlist.common_padding_attlist_.fo_padding_) { padding_common = style_cell_attlist.common_padding_attlist_.fo_padding_->get_value_unit(odf_types::length::emu); } else if (graphic_props && graphic_props->common_padding_attlist_.fo_padding_) { padding_common = graphic_props->common_padding_attlist_.fo_padding_->get_value_unit(odf_types::length::emu); } if (style_cell_attlist.common_padding_attlist_.fo_padding_top_) { double padding = style_cell_attlist.common_padding_attlist_.fo_padding_top_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marT", (long)padding); } else if (graphic_props && graphic_props->common_padding_attlist_.fo_padding_top_) { double padding = graphic_props->common_padding_attlist_.fo_padding_top_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marT", (long)padding); } else if (padding_common > 0) CP_XML_ATTR(L"marT", (long)padding_common); if (style_cell_attlist.common_padding_attlist_.fo_padding_bottom_) { double padding = style_cell_attlist.common_padding_attlist_.fo_padding_bottom_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marB", (long)padding); } else if (graphic_props && graphic_props->common_padding_attlist_.fo_padding_bottom_) { double padding = graphic_props->common_padding_attlist_.fo_padding_bottom_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marB", (long)padding); } else if (padding_common > 0) CP_XML_ATTR(L"marB", (long)padding_common); if (style_cell_attlist.common_padding_attlist_.fo_padding_left_) { double padding = style_cell_attlist.common_padding_attlist_.fo_padding_left_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marL", (long)padding); } else if (graphic_props && graphic_props->common_padding_attlist_.fo_padding_left_) { double padding = graphic_props->common_padding_attlist_.fo_padding_left_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marL", (long)padding); } else if (padding_common > 0) CP_XML_ATTR(L"marL", (long)padding_common); if (style_cell_attlist.common_padding_attlist_.fo_padding_right_) { double padding = style_cell_attlist.common_padding_attlist_.fo_padding_right_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marR", (long)padding); } else if (graphic_props && graphic_props->common_padding_attlist_.fo_padding_right_) { double padding = graphic_props->common_padding_attlist_.fo_padding_right_->get_value_unit(odf_types::length::emu); CP_XML_ATTR(L"marR", (long)padding); } else if (padding_common > 0) CP_XML_ATTR(L"marR", (long)padding_common); //vert // //style_cell_attlist.pptx_serialize(Context, CP_XML_STREAM()); //nodes odf_reader::paragraph_format_properties style_paragraph = odf_reader::calc_paragraph_properties_content(instances);//instances); pptx_border_edge left, top, bottom, right; process_border(left, style_paragraph.fo_border_left_ ? style_paragraph.fo_border_left_ : style_paragraph.fo_border_); process_border(top, style_paragraph.fo_border_top_ ? style_paragraph.fo_border_top_ : style_paragraph.fo_border_); process_border(right, style_paragraph.fo_border_right_ ? style_paragraph.fo_border_right_ : style_paragraph.fo_border_); process_border(bottom, style_paragraph.fo_border_bottom_ ? style_paragraph.fo_border_bottom_ : style_paragraph.fo_border_); oox_serialize_border(CP_XML_STREAM(), L"a:lnL", left); oox_serialize_border(CP_XML_STREAM(), L"a:lnR", right); oox_serialize_border(CP_XML_STREAM(), L"a:lnT", top); oox_serialize_border(CP_XML_STREAM(), L"a:lnB", bottom); //диагональных в оо нет. //////////////////////////////////////////////////////////////////////////////////////////////// oox::_oox_fill fill; if (graphic_props) { odf_reader::Compute_GraphicFill(graphic_props->common_draw_fill_attlist_, graphic_props->style_background_image_, Context.root(), fill); } if (fill.bitmap) { bool isMediaInternal = true; std::wstring ref; fill.bitmap->rId = Context.get_slide_context().get_mediaitems()->add_or_find(fill.bitmap->xlink_href_, oox::typeImage, isMediaInternal, ref, oox::document_place); Context.get_slide_context().add_rels(isMediaInternal, fill.bitmap->rId, ref, oox::typeImage); } oox::oox_serialize_fill(CP_XML_STREAM(), fill); ///////////////////////////////////////////////////////////////////////////////// //headers (Header Cells Associated With Table Cell) §21.1.3.4 //lnBlToTr (Bottom-Left to Top-Right Border Line Properties) §21.1.3.6 //lnTlToBr (Top-Left to Bottom-Right Border Line Properties) } } } } } }