mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 06:22:44 +08:00
1531 lines
53 KiB
C++
1531 lines
53 KiB
C++
/*
|
|
* (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 "table.h"
|
|
|
|
#include <xml/utils.h>
|
|
#include "odf_document.h"
|
|
#include <xml/simple_xml_writer.h>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include "serialize_elements.h"
|
|
#include "odfcontext.h"
|
|
#include "number_style.h"
|
|
#include "calcs_styles.h"
|
|
#include "search_table_cell.h"
|
|
|
|
#include "../../Reader/Converter/xlsx_utils.h"
|
|
#include "../../Reader/Converter/xlsx_cell_format.h"
|
|
#include "../../Formulas/formulasconvert.h"
|
|
|
|
namespace cpdoccore {
|
|
|
|
using namespace odf_types;
|
|
|
|
namespace odf_reader {
|
|
|
|
static formulasconvert::odf2oox_converter formulas_converter;
|
|
|
|
|
|
int table_table_cell_content::xlsx_convert(oox::xlsx_conversion_context & Context, text_format_properties_ptr text_properties, bool need_cache)
|
|
{
|
|
if (elements_.empty()) return -1;
|
|
|
|
Context.get_table_context().start_cell_content();
|
|
Context.get_text_context()->set_cell_text_properties(text_properties);
|
|
|
|
for (size_t i = 0 ; i < elements_.size(); i++)
|
|
{
|
|
elements_[i]->xlsx_convert(Context);
|
|
if ((elements_[i]->get_type() == typeTextP) && (i < elements_.size() - 1) && (elements_[i + 1]->get_type() == typeTextP))
|
|
{
|
|
Context.get_text_context()->start_paragraph(L"");
|
|
Context.get_text_context()->start_span(L"");
|
|
Context.get_text_context()->add_text(L"\n");
|
|
Context.get_text_context()->end_span();
|
|
Context.get_text_context()->end_paragraph();
|
|
}
|
|
}
|
|
|
|
const int sharedStrId = Context.get_table_context().end_cell_content(need_cache);
|
|
return sharedStrId;
|
|
}
|
|
|
|
void table_table_row::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
bool bEndTable = Context.get_table_context().state()->get_end_table();
|
|
|
|
if (attlist_.table_number_rows_repeated_ > 1 && empty())
|
|
{
|
|
Context.get_table_context().state()->add_empty_row(attlist_.table_number_rows_repeated_, bHeader);
|
|
return;
|
|
}
|
|
if (attlist_.table_number_rows_repeated_ > 0x0f00 && empty_content_cells(false) || bEndTable)//0xf000 - conv_KDZO3J3xLIbZ5fC0HR0__xlsx.ods
|
|
{
|
|
Context.get_table_context().state()->set_end_table();
|
|
Context.get_table_context().state()->add_empty_row(attlist_.table_number_rows_repeated_, bHeader);
|
|
return; //conv_hSX8n3lVbhALjt0aafg__xlsx.ods, conv_MA2CauoNfX_7ejKS5eg__xlsx.ods
|
|
}
|
|
|
|
std::wostream & strm = Context.current_sheet().sheetData();
|
|
///processing styles for row -
|
|
size_t Default_Cell_style_in_row_ = 0;
|
|
|
|
const std::wstring rowStyleName = attlist_.table_style_name_.get_value_or(L"");
|
|
const std::wstring defaultCellStyleName = attlist_.table_default_cell_style_name_.get_value_or( L"");
|
|
|
|
style_instance * instStyle_CellDefault =
|
|
Context.root()->odf_context().styleContainer().style_by_name(defaultCellStyleName, style_family::TableCell, false/*false*/);
|
|
|
|
style_table_cell_properties * prop_CellDefault = NULL;
|
|
|
|
if ((instStyle_CellDefault) && (instStyle_CellDefault->content()))
|
|
prop_CellDefault = instStyle_CellDefault->content()->get_style_table_cell_properties();
|
|
//custom cell style settings for this row
|
|
|
|
if (prop_CellDefault) //check if there is any custom for row - then calculate style
|
|
{
|
|
odf_reader::style_table_cell_properties_attlist cellFormatProperties = calc_table_cell_properties(instStyle_CellDefault);
|
|
Default_Cell_style_in_row_ = Context.get_style_manager().xfId(NULL,NULL, &cellFormatProperties, NULL, L"", 0, true);
|
|
}
|
|
else //no cell style for row - let's look inside the row at the last cell
|
|
{
|
|
//take style from last cell if it's repeating (then don't need to write empty cells)
|
|
int ind_last_cell = content_.size()-1;
|
|
table_table_cell *last_cell = NULL;
|
|
if (ind_last_cell > 0)
|
|
last_cell = dynamic_cast<table_table_cell *>(content_[ind_last_cell].get());
|
|
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
bool skip_next_row = false;
|
|
|
|
std::wstring ht = L"";
|
|
double row_height = 0.0;
|
|
|
|
bool bBreakAfter = false, bBreakBefore = false;
|
|
|
|
odf_read_context & odfContext = Context.root()->odf_context();
|
|
|
|
odf_reader::style_instance * rowStyle = odfContext.styleContainer().style_by_name(rowStyleName, odf_types::style_family::TableRow,false/*false*/);
|
|
if ((rowStyle) && (rowStyle->content()))
|
|
{
|
|
const odf_reader::style_table_row_properties * prop = rowStyle->content()->get_style_table_row_properties();
|
|
if ((prop) && (prop->attlist_.style_row_height_))
|
|
{
|
|
row_height = prop->attlist_.style_row_height_->get_value_unit(odf_types::length::pt);
|
|
|
|
if ((prop->attlist_.style_use_optimal_row_height_) &&
|
|
(*prop->attlist_.style_use_optimal_row_height_==true))
|
|
{
|
|
//automatic height adjustment.
|
|
//not present in oox
|
|
//todooo calculate size based on current font (double) and compare with specified - override!!!
|
|
}
|
|
|
|
std::wstringstream ht_s;
|
|
ht_s.precision(3);
|
|
ht_s << std::fixed << row_height;
|
|
ht = ht_s.str();
|
|
}
|
|
if ((prop->attlist_.common_break_attlist_.fo_break_before_) &&
|
|
(prop->attlist_.common_break_attlist_.fo_break_before_->get_type() == odf_types::fo_break::Page))
|
|
{
|
|
bBreakBefore = true;
|
|
}
|
|
else if ((prop) && ((prop->attlist_.common_break_attlist_.fo_break_after_) &&
|
|
(prop->attlist_.common_break_attlist_.fo_break_after_->get_type() == odf_types::fo_break::Page)))
|
|
{
|
|
bBreakAfter = true;
|
|
}
|
|
}
|
|
int row_current = Context.current_table_row() + 1;
|
|
|
|
bool hidden = attlist_.table_visibility_.get_type() == table_visibility::Collapse;
|
|
bool filter = attlist_.table_visibility_.get_type() == table_visibility::Filter;
|
|
|
|
for (unsigned int i = 0; i < attlist_.table_number_rows_repeated_; ++i)
|
|
{
|
|
Context.get_table_context().state()->start_row(rowStyleName, defaultCellStyleName, bHeader);
|
|
|
|
if (bBreakBefore) Context.get_table_context().state()->set_row_break_before();
|
|
if (bBreakAfter) Context.get_table_context().state()->set_row_break_after();
|
|
|
|
if (!skip_next_row)
|
|
{
|
|
CP_XML_WRITER(strm)
|
|
{
|
|
CP_XML_NODE(L"row")
|
|
{
|
|
CP_XML_ATTR(L"r", Context.current_table_row() + 1);
|
|
|
|
if (false == Context.get_table_context().state()->group_rows_.empty())
|
|
{
|
|
//std::wstring str_spans = std::to_wstring(Context.get_table_context().state()->group_row_.count);
|
|
//str_spans = str_spans + L":";
|
|
int columns = Context.get_table_context().columns_count();
|
|
if (columns > 0x4000) columns = 0x4000;
|
|
std::wstring str_spans = L"1:" + std::to_wstring(columns);
|
|
ht = L"";
|
|
|
|
CP_XML_ATTR(L"collapsed", Context.get_table_context().state()->group_rows_.back());
|
|
CP_XML_ATTR(L"outlineLevel", Context.get_table_context().state()->group_rows_.size());
|
|
CP_XML_ATTR(L"spans", str_spans);
|
|
|
|
if (Context.get_table_context().state()->group_rows_.back()) hidden = false;
|
|
}
|
|
|
|
if (hidden || filter)
|
|
{
|
|
CP_XML_ATTR(L"hidden", 1);
|
|
}
|
|
|
|
if (!ht.empty())
|
|
{
|
|
CP_XML_ATTR(L"ht", ht);
|
|
CP_XML_ATTR(L"customHeight", 1);
|
|
}
|
|
if (Default_Cell_style_in_row_ > 0)
|
|
{
|
|
CP_XML_ATTR(L"customFormat", 1);
|
|
CP_XML_ATTR(L"s", Default_Cell_style_in_row_ );
|
|
}
|
|
|
|
|
|
CP_XML_STREAM();
|
|
|
|
for (size_t i = 0 ; i < content_.size(); i++)
|
|
{
|
|
office_element_ptr & elm = content_[i];
|
|
|
|
if (i == content_.size() - 1) //mark last cell in row (for skip empty styled)
|
|
{
|
|
table_table_cell *cell = dynamic_cast<table_table_cell*> (elm.get());
|
|
table_covered_table_cell *covered_cell = dynamic_cast<table_covered_table_cell*>(elm.get());
|
|
|
|
if (cell) cell->last_cell_ = true;
|
|
else if (covered_cell) covered_cell->last_cell_ = true;
|
|
}
|
|
elm->xlsx_convert(Context);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
Context.get_table_context().state()->end_row();
|
|
|
|
if (Context.get_table_context().state()->is_empty_row() && Context.get_table_context().state()->group_rows_.empty())
|
|
{
|
|
skip_next_row = true;
|
|
if (attlist_.table_number_rows_repeated_ > 0xf000)
|
|
break;//Notification_of_delivery.ods (1st sheet)
|
|
}
|
|
if (content_.size() > 0 && attlist_.table_number_rows_repeated_ > 1000)
|
|
{
|
|
table_table_cell * table_cell = dynamic_cast<table_table_cell *>(content_[0].get());
|
|
if ((table_cell) && (table_cell->attlist_.table_number_columns_repeated_ > 1000))
|
|
{
|
|
break;//Notification_of_delivery.ods (2nd sheet)
|
|
}
|
|
}
|
|
}
|
|
|
|
Context.get_table_metrics().add_rows(attlist_.table_number_rows_repeated_, !hidden ? row_height : 0.0);
|
|
|
|
}
|
|
|
|
void table_table_rows::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0; i < content_.size(); i++)
|
|
{
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_table_header_rows::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0; i < content_.size(); i++)
|
|
{
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_rows::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
if (table_table_rows_)
|
|
table_table_rows_->xlsx_convert(Context);
|
|
else
|
|
{
|
|
while (table_table_row_.size() > 1)
|
|
{
|
|
table_table_row* row_last = dynamic_cast<table_table_row*>(table_table_row_[table_table_row_.size() - 1].get());
|
|
table_table_row* row_last_1 = dynamic_cast<table_table_row*>(table_table_row_[table_table_row_.size() - 2].get());
|
|
|
|
std::wstring style = row_last->attlist_.table_style_name_.get_value_or(L"");
|
|
std::wstring style_1 = row_last->attlist_.table_style_name_.get_value_or(L"");
|
|
|
|
if (style != style_1)break;
|
|
if (row_last_1->empty_content_cells() == false) break;
|
|
if (row_last->empty_content_cells() == false) break;
|
|
|
|
row_last_1->attlist_.table_number_rows_repeated_ += row_last->attlist_.table_number_rows_repeated_;
|
|
table_table_row_.pop_back();
|
|
}
|
|
for (size_t i = 0; i < table_table_row_.size(); i++)
|
|
{
|
|
table_table_row_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
}
|
|
|
|
void table_rows_no_group::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
table_rows_1_.xlsx_convert(Context);
|
|
|
|
if (table_table_header_rows_)
|
|
table_table_header_rows_->xlsx_convert(Context);
|
|
|
|
table_rows_2_.xlsx_convert(Context);
|
|
}
|
|
|
|
void table_rows_and_groups::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0; i < content_.size(); i++)
|
|
{
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_table_row_group::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
Context.get_table_context().state()->start_table_row_group(attlist_.table_display_);
|
|
table_rows_and_groups_.xlsx_convert(Context);
|
|
Context.get_table_context().state()->end_table_row_group();
|
|
}
|
|
|
|
void table_table::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
std::wstring tableStyleName = attlist_.table_style_name_.get_value_or(L"");
|
|
std::wstring tableName = attlist_.table_name_.get_value_or(L"");
|
|
|
|
_CP_LOG << L"[info][xlsx] process table \"" << tableName << L"\"\n" << std::endl;
|
|
|
|
if (office_forms_)
|
|
{
|
|
office_forms_->xlsx_convert(Context);
|
|
}
|
|
|
|
std::wstring externalRef;
|
|
std::wstring externalRef2;
|
|
|
|
if (table_table_source_)
|
|
{
|
|
table_table_source* table_source = dynamic_cast<table_table_source*>( table_table_source_.get() );
|
|
if ( table_source)
|
|
{
|
|
if (table_source->table_linked_source_attlist_.xlink_attlist_.href_)
|
|
{
|
|
externalRef = *table_source->table_linked_source_attlist_.xlink_attlist_.href_;
|
|
}
|
|
if (table_source->attlist_.table_table_name_)
|
|
{
|
|
externalRef2 = tableName; // - used in formula
|
|
tableName = *table_source->attlist_.table_table_name_; // - only link to file
|
|
|
|
size_t pos = externalRef2.find(L"#");
|
|
if (pos != std::wstring::npos) externalRef2 = externalRef2.substr(0, pos);
|
|
XmlUtils::replace_all(externalRef2, L"'", L"");
|
|
}
|
|
}
|
|
}
|
|
Context.start_table(tableName, tableStyleName, externalRef2);
|
|
|
|
if (attlist_.table_protected_)
|
|
{
|
|
Context.get_table_context().set_protection(true, attlist_.table_protection_key_.get_value_or(L""),
|
|
attlist_.table_protection_key_digest_algorithm_.get_value_or(L""));
|
|
table_table_protection* prot = dynamic_cast<table_table_protection*>( table_protection_.get() );
|
|
if (prot)
|
|
{
|
|
if (prot->select_protected_cells)
|
|
Context.get_table_context().state()->set_protection_select_protected_cells(*prot->select_protected_cells);
|
|
if (prot->select_unprotected_cells)
|
|
Context.get_table_context().state()->set_protection_select_unprotected_cells(*prot->select_unprotected_cells);
|
|
|
|
if (prot->insert_columns)
|
|
Context.get_table_context().state()->set_protection_insert_columns(*prot->insert_columns);
|
|
if (prot->insert_rows)
|
|
Context.get_table_context().state()->set_protection_insert_rows(*prot->insert_rows);
|
|
if (prot->delete_columns)
|
|
Context.get_table_context().state()->set_protection_delete_columns(*prot->delete_columns);
|
|
if (prot->delete_rows)
|
|
Context.get_table_context().state()->set_protection_delete_rows(*prot->delete_rows);
|
|
}
|
|
}
|
|
|
|
if (attlist_.table_print_ranges_)
|
|
{
|
|
Context.get_table_context().set_print_area(*attlist_.table_print_ranges_);
|
|
}
|
|
table_columns_and_groups_.xlsx_convert(Context);
|
|
|
|
// check last rows for equal style and empties - collapsed
|
|
|
|
//<table:table-row table:style-name="ro3" table:number-rows-repeated="65353">
|
|
// <table:table-cell table:style-name="ce14" table:number-columns-repeated="5"/>
|
|
// <table:table-cell table:number-columns-repeated="1019"/>
|
|
//</table:table-row>
|
|
//<table:table-row table:style-name="ro3" table:number-rows-repeated="983017">
|
|
// <table:table-cell table:number-columns-repeated="1024"/>
|
|
//</table:table-row>
|
|
//<table:table-row table:style-name="ro3">
|
|
// <table:table-cell table:number-columns-repeated="1024"/>
|
|
//</table:table-row>
|
|
|
|
if (table_rows_and_groups_.content_.empty() == false && table_rows_and_groups_.content_.back()->get_type() == typeTableTableRowNoGroup)
|
|
{
|
|
table_rows_no_group * rows = dynamic_cast<table_rows_no_group*>(table_rows_and_groups_.content_.back().get());
|
|
rows->table_rows_1_.remove_equals_empty();
|
|
rows->table_rows_2_.remove_equals_empty();
|
|
}
|
|
|
|
table_rows_and_groups_.xlsx_convert(Context);
|
|
|
|
if (table_shapes_)
|
|
table_shapes_->xlsx_convert(Context);
|
|
|
|
if (conditional_formats_)
|
|
conditional_formats_->xlsx_convert(Context);
|
|
|
|
if (sparkline_groups_)
|
|
{
|
|
sparkline_groups_->xlsx_convert(Context);
|
|
}
|
|
|
|
for (size_t i = 0 ; i < table_named_.size(); i++)
|
|
{
|
|
table_named_[i]->xlsx_convert(Context);
|
|
}
|
|
|
|
Context.end_table();
|
|
}
|
|
|
|
void table_columns::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
if (table_table_columns_)
|
|
table_table_columns_->xlsx_convert(Context);
|
|
|
|
for (size_t i = 0; i < table_table_column_.size(); i++)
|
|
{
|
|
table_table_column_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_columns_no_group::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
table_columns_1_.xlsx_convert(Context);
|
|
|
|
if (table_table_header_columns_)
|
|
table_table_header_columns_->xlsx_convert(Context);
|
|
|
|
table_columns_2_.xlsx_convert(Context);
|
|
}
|
|
|
|
void table_columns_and_groups::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0; i < content_.size(); i++)
|
|
{
|
|
office_element_ptr & elm = content_[i];
|
|
elm->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_table_header_columns::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0; i < content_.size(); i++)
|
|
{
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
|
|
void table_table_column_group::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
Context.get_table_context().state()->start_table_column_group(attlist_.table_display_);
|
|
table_columns_and_groups_.xlsx_convert(Context);
|
|
Context.get_table_context().state()->end_table_column_group();
|
|
}
|
|
|
|
namespace {
|
|
// see ECMA-376 page 1768
|
|
|
|
double pixToSize(double pixels, double maxDigitSize)
|
|
{
|
|
if (pixels < 8) pixels = 8; //NOTIFICATION_OF_ARRIVAL_OF_FOREIGN_CITIZEN.ods
|
|
|
|
return (int(( pixels /*/ 0.75*/ - 5)/ maxDigitSize * 100. + 0.5)) /100. * 0.98; // * 9525. * 72.0 / (360000.0 * 2.54);
|
|
}
|
|
|
|
}
|
|
|
|
void table_table_column::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
std::wostream & strm = Context.current_sheet().cols();
|
|
|
|
const unsigned int columnsRepeated = attlist_.table_number_columns_repeated_;
|
|
const std::wstring styleName = attlist_.table_style_name_.get_value_or(L"");
|
|
const std::wstring defaultCellStyleName = attlist_.table_default_cell_style_name_.get_value_or(L"");
|
|
|
|
|
|
int cMin = 0, cMax = 0;
|
|
Context.start_table_column(columnsRepeated, defaultCellStyleName, cMin, cMax, bHeader);
|
|
|
|
if ( cMin > 16384 ) return;
|
|
if ( cMax > 16384 ) return;
|
|
|
|
double pt_width = 0.0;
|
|
double cm_width = 0.0;
|
|
double in_width = 0.0;
|
|
|
|
CP_XML_WRITER(strm)
|
|
{
|
|
CP_XML_NODE(L"col")
|
|
{
|
|
bool hidden = attlist_.table_visibility_.get_type() == table_visibility::Collapse;
|
|
|
|
if (false == Context.get_table_context().state()->group_columns_.empty())
|
|
{
|
|
CP_XML_ATTR(L"outlineLevel", Context.get_table_context().state()->group_columns_.size());
|
|
CP_XML_ATTR(L"collapsed", Context.get_table_context().state()->group_columns_.back());
|
|
|
|
if (Context.get_table_context().state()->group_columns_.back()) hidden = false;
|
|
}
|
|
if (hidden)
|
|
{
|
|
CP_XML_ATTR(L"hidden", L"true");
|
|
}
|
|
|
|
CP_XML_ATTR(L"max", cMax);
|
|
CP_XML_ATTR(L"min", (cMin + 1));
|
|
|
|
if (attlist_.table_style_name_)
|
|
{
|
|
|
|
if (style_instance * inst =
|
|
Context.root()->odf_context().styleContainer().style_by_name(defaultCellStyleName, style_family::TableCell, false/*false*/))
|
|
{
|
|
if (inst->content())
|
|
{
|
|
if (const style_table_cell_properties * prop = inst->content()->get_style_table_cell_properties())
|
|
{//add check so that default, i.e. empty style, doesn't get here
|
|
odf_reader::style_table_cell_properties_attlist cellFormatProperties = calc_table_cell_properties(inst);
|
|
|
|
bool set_default = false;
|
|
if (columnsRepeated > 100) set_default = true;
|
|
|
|
size_t style_ = Context.get_style_manager().xfId(NULL, NULL, &cellFormatProperties, NULL, L"", 0, set_default);
|
|
|
|
//if (set_default)
|
|
// CP_XML_ATTR(L"style", style_ );
|
|
}
|
|
}
|
|
}
|
|
_CP_OPT(double) width;
|
|
const std::wstring colStyleName = attlist_.table_style_name_.get_value_or(L"");
|
|
if (style_instance * inst = Context.root()->odf_context().styleContainer().style_by_name(colStyleName, style_family::TableColumn, false))
|
|
{
|
|
if (inst->content())
|
|
{
|
|
if (const style_table_column_properties * prop = inst->content()->get_style_table_column_properties())
|
|
{
|
|
if ((prop->attlist_.loext_column_width_sym_) && (*prop->attlist_.loext_column_width_sym_ > 0))
|
|
{
|
|
width = *prop->attlist_.loext_column_width_sym_;
|
|
|
|
CP_XML_ATTR(L"width", *width);
|
|
CP_XML_ATTR(L"customWidth", true);
|
|
Context.table_column_last_width(*width);
|
|
}
|
|
if (prop->attlist_.style_column_width_)
|
|
{
|
|
pt_width = prop->attlist_.style_column_width_->get_value_unit(length::pt);
|
|
cm_width = prop->attlist_.style_column_width_->get_value_unit(length::cm);
|
|
in_width = prop->attlist_.style_column_width_->get_value_unit(length::inch);
|
|
|
|
if (!width)
|
|
{
|
|
if (hidden)
|
|
{
|
|
in_width = 0.0;
|
|
}
|
|
|
|
const double pixDpi = in_width * 96.;
|
|
width = pixToSize(pixDpi, Context.getMaxDigitSize().first);
|
|
|
|
// see ECMA-376 page 1768
|
|
if (in_width > 0)
|
|
CP_XML_ATTR(L"width", *width);
|
|
|
|
CP_XML_ATTR(L"customWidth", true);
|
|
Context.table_column_last_width(*width);
|
|
}
|
|
}
|
|
if ((prop->attlist_.common_break_attlist_.fo_break_before_) &&
|
|
(prop->attlist_.common_break_attlist_.fo_break_before_->get_type() == odf_types::fo_break::Page))
|
|
{
|
|
Context.get_table_context().state()->set_column_break_before();
|
|
}
|
|
else if ((prop->attlist_.common_break_attlist_.fo_break_after_) &&
|
|
(prop->attlist_.common_break_attlist_.fo_break_after_->get_type() == odf_types::fo_break::Page))
|
|
{
|
|
Context.get_table_context().state()->set_column_break_after();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!width)//??? default set
|
|
{
|
|
width = 11.52;
|
|
CP_XML_ATTR(L"width", *width);
|
|
CP_XML_ATTR(L"customWidth", false);
|
|
Context.table_column_last_width(*width);
|
|
}
|
|
}
|
|
|
|
} // col
|
|
} // CP_XML_WRITER
|
|
|
|
if (pt_width < 1)
|
|
{
|
|
pt_width = 2.26 * 28.34467120181406; // 2.26 cm default
|
|
}
|
|
Context.get_table_metrics().add_cols(cMax - cMin, pt_width);
|
|
Context.end_table_column();
|
|
}
|
|
|
|
namespace {
|
|
|
|
std::wstring SearchCellDataStyle(oox::xlsx_conversion_context & Context, std::wstring const & styleName)
|
|
{
|
|
odf_read_context & odfContext = Context.root()->odf_context();
|
|
|
|
std::wstring styleStr = styleName;
|
|
|
|
for (;;)
|
|
{
|
|
style_instance * styleInstance =
|
|
odfContext.styleContainer().style_by_name(styleStr, style_family::TableCell,false);
|
|
|
|
if (!styleInstance->data_style_name().empty())
|
|
return styleInstance->data_style_name();
|
|
|
|
if (!styleInstance->parent_name().empty())
|
|
styleStr = styleInstance->parent_name();
|
|
else
|
|
break;
|
|
}
|
|
return L"";
|
|
}
|
|
|
|
std::wstring SearchCellDataStyle(oox::xlsx_conversion_context & Context, style_instance * styleInstance)
|
|
{
|
|
if (!styleInstance)
|
|
return L"";
|
|
|
|
odf_read_context & odfContext = Context.root()->odf_context();
|
|
|
|
for (;;)
|
|
{
|
|
if (!styleInstance->data_style_name().empty())
|
|
return styleInstance->data_style_name();
|
|
|
|
if (styleInstance->parent())
|
|
styleInstance = styleInstance->parent();
|
|
else
|
|
break;
|
|
}
|
|
return L"";
|
|
}
|
|
|
|
std::wstring CalcCellDataStyle(oox::xlsx_conversion_context & Context,
|
|
std::wstring const & defaultColumnCellStyleName,
|
|
std::wstring const & defaultRowCellStyleName,
|
|
std::wstring const & cellStyleName
|
|
)
|
|
{
|
|
odf_read_context & odfContext = Context.root()->odf_context();
|
|
|
|
style_instance * defaultCellStyle = odfContext.styleContainer().style_default_by_type(style_family::TableCell);
|
|
style_instance * defaultColumnCellStyle = odfContext.styleContainer().style_by_name (defaultColumnCellStyleName, style_family::TableCell,false);
|
|
style_instance * defaultRowCellStyle = odfContext.styleContainer().style_by_name(defaultRowCellStyleName, style_family::TableCell,false);
|
|
style_instance * cellStyle = odfContext.styleContainer().style_by_name(cellStyleName, style_family::TableCell,false);
|
|
|
|
std::wstring data_style = L"";
|
|
if (defaultCellStyle)
|
|
data_style = SearchCellDataStyle(Context, defaultCellStyle);
|
|
|
|
{
|
|
std::wstring ds1 = SearchCellDataStyle(Context, defaultColumnCellStyle);
|
|
if (!ds1.empty())
|
|
data_style = ds1;
|
|
}
|
|
|
|
{
|
|
std::wstring ds1 = SearchCellDataStyle(Context, defaultRowCellStyle);
|
|
if (!ds1.empty())
|
|
data_style = ds1;
|
|
}
|
|
|
|
{
|
|
std::wstring ds1 = SearchCellDataStyle(Context, cellStyle);
|
|
if (!ds1.empty())
|
|
data_style = ds1;
|
|
}
|
|
return data_style;
|
|
}
|
|
|
|
}
|
|
|
|
void table_table_cell::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
bool bExternalTable = !Context.current_sheet().external_ref().empty();
|
|
|
|
std::wostream & strm = Context.current_sheet().sheetData();
|
|
|
|
const common_value_and_type_attlist & attr = attlist_.common_value_and_type_attlist_;
|
|
std::wstring formula = attlist_.table_formula_.get_value_or(L"");
|
|
|
|
|
|
if (attlist_.table_number_columns_repeated_ < 199 && last_cell_) last_cell_ = false;
|
|
|
|
unsigned int cell_repeated_max = Context.current_table_column() + attlist_.table_number_columns_repeated_ + 1;
|
|
|
|
std::wstring rowStyleName = Context.get_table_context().default_row_cell_style();
|
|
std::wstring cellStyleName = attlist_.table_style_name_.get_value_or(L"");
|
|
|
|
std::wstring num_format;
|
|
office_value_type::type num_format_type = office_value_type::Custom;
|
|
|
|
std::wstring number_val;
|
|
_CP_OPT(bool) bool_val;
|
|
_CP_OPT(std::wstring) str_val;
|
|
|
|
oox::XlsxCellType::type xlsx_value_type = oox::XlsxCellType::s;
|
|
|
|
office_value_type::type odf_value_type = office_value_type::Custom;
|
|
if (attr.office_value_type_)
|
|
odf_value_type = attr.office_value_type_->get_type();
|
|
|
|
if ((odf_value_type == office_value_type::Float) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_value_))// ??
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
|
|
if (num_format_type == office_value_type::Time ||
|
|
num_format_type == office_value_type::Date ||
|
|
num_format_type == office_value_type::Currency)
|
|
{//data format type from style doesn't match cell data format
|
|
num_format.clear();
|
|
num_format_type = office_value_type::Custom;
|
|
}
|
|
}
|
|
else if (odf_value_type == office_value_type::Percentage)
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
|
|
if (num_format_type == office_value_type::Time ||
|
|
num_format_type == office_value_type::Date ||
|
|
num_format_type == office_value_type::Currency)
|
|
{//data format type from style doesn't match cell data format
|
|
num_format.clear();
|
|
num_format_type = office_value_type::Percentage;
|
|
}
|
|
}
|
|
else if (odf_value_type == office_value_type::Currency)
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
}
|
|
else if ((odf_value_type == office_value_type::Date) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_date_value_))
|
|
{
|
|
if (attr.office_date_value_)
|
|
{
|
|
int y, m, d;
|
|
_CP_OPT(int) h, min, sec;
|
|
if (oox::parseDateTime(attr.office_date_value_.get(), y, m, d, h, min, sec))
|
|
{
|
|
boost::int64_t intDate = oox::convertDate(y, m, d);
|
|
_CP_OPT(double) dTime;
|
|
if (h && min)
|
|
{
|
|
dTime = oox::convertTime(*h, *min, sec.get_value_or(0));
|
|
}
|
|
if (intDate > 0)
|
|
{
|
|
if (dTime)
|
|
{
|
|
number_val = XmlUtils::ToString(*dTime + intDate);
|
|
}
|
|
else
|
|
{
|
|
number_val = boost::lexical_cast<std::wstring>(intDate);
|
|
}
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
|
|
if (num_format_type == office_value_type::Currency)
|
|
{//data format type from style doesn't match cell data format
|
|
num_format.clear();
|
|
num_format_type = office_value_type::Date;
|
|
}
|
|
|
|
if (num_format.empty())
|
|
num_format = Context.get_num_format_context().get_last_date_format();
|
|
}
|
|
else
|
|
{
|
|
str_val = attr.office_date_value_.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((odf_value_type == office_value_type::Time) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_time_value_))
|
|
{
|
|
if (attr.office_time_value_)
|
|
{
|
|
const std::wstring tv = attr.office_time_value_.get();
|
|
int h, m;
|
|
double s;
|
|
if (oox::parseTime(tv, h, m, s))
|
|
{
|
|
double dTime = oox::convertTime(h, m, s);
|
|
if (dTime >= 0)
|
|
{
|
|
number_val = boost::lexical_cast<std::wstring>(dTime);
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
|
|
if (num_format_type == office_value_type::Currency)
|
|
{//data format type from style doesn't match cell data format
|
|
num_format.clear();
|
|
num_format_type = office_value_type::Time;
|
|
}
|
|
|
|
if (num_format.empty())
|
|
num_format = Context.get_num_format_context().get_last_time_format();
|
|
}
|
|
else
|
|
{
|
|
str_val = tv;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((odf_value_type == office_value_type::Boolean) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_boolean_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::b;
|
|
if (attr.office_boolean_value_) bool_val = oox::parseBoolVal(attr.office_boolean_value_.get());
|
|
|
|
num_format.clear();
|
|
num_format_type = office_value_type::Boolean;
|
|
}
|
|
else if ((odf_value_type == office_value_type::String) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_string_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::str;
|
|
if (attr.office_string_value_) str_val = attr.office_string_value_.get();
|
|
|
|
num_format.clear();
|
|
num_format_type = office_value_type::String;
|
|
}
|
|
|
|
bool is_data_visible = (false == content_.elements_.empty() ||
|
|
attlist_.table_content_validation_name_ || !formula.empty() || !number_val.empty() || str_val || bool_val);
|
|
|
|
if (cell_repeated_max >= 1024 && cellStyleName.empty() && last_cell_ && !is_data_visible)
|
|
{//Book 24.ods
|
|
return;
|
|
}
|
|
int sharedStringId = -1;
|
|
int empty_cell_count = 0;
|
|
bool skip_next_cell = false;
|
|
|
|
bool need_cache_convert = false;
|
|
if (number_val.empty() && !bool_val)
|
|
{
|
|
if (false == formula.empty())
|
|
xlsx_value_type = oox::XlsxCellType::str;
|
|
else
|
|
{
|
|
need_cache_convert = true;
|
|
}
|
|
}
|
|
// calculate style for cell
|
|
//---------------------------------------------------------------------------------------------------------
|
|
std::wstring columnStyleName = Context.get_table_context().default_column_cell_style(); // different column styles may exist with repeated (Book 24.ods)
|
|
|
|
odf_read_context& odfContext = Context.root()->odf_context();
|
|
|
|
style_instance* defaultCellStyle = NULL, * defaultColumnCellStyle = NULL, * defaultRowCellStyle = NULL, * cellStyle = NULL;
|
|
try
|
|
{
|
|
if (is_present_hyperlink_)
|
|
{
|
|
defaultCellStyle = odfContext.styleContainer().style_by_name(L"Hyperlink", style_family::TableCell, true);
|
|
}
|
|
if (!defaultCellStyle)
|
|
{
|
|
defaultCellStyle = odfContext.styleContainer().style_default_by_type(style_family::TableCell);
|
|
}
|
|
|
|
defaultColumnCellStyle = odfContext.styleContainer().style_by_name(columnStyleName, style_family::TableCell, false);
|
|
defaultRowCellStyle = odfContext.styleContainer().style_by_name(rowStyleName, style_family::TableCell, false);
|
|
cellStyle = odfContext.styleContainer().style_by_name(cellStyleName, style_family::TableCell, false);
|
|
}
|
|
catch (...)
|
|
{
|
|
_CP_LOG << L"[error]: style wrong\n";
|
|
}
|
|
|
|
std::wstring data_style = CalcCellDataStyle(Context, columnStyleName, rowStyleName, cellStyleName);
|
|
|
|
// styles are not inherited
|
|
std::vector<const style_instance*> instances;
|
|
instances.push_back(defaultCellStyle);
|
|
|
|
if (defaultColumnCellStyle)
|
|
instances.push_back(defaultColumnCellStyle);
|
|
|
|
if (defaultRowCellStyle)
|
|
{
|
|
if (instances.size() > 1)
|
|
instances[1] = defaultRowCellStyle;
|
|
else
|
|
instances.push_back(defaultRowCellStyle);
|
|
}
|
|
|
|
if (cellStyle)
|
|
{
|
|
if (instances.size() > 1)
|
|
instances[1] = cellStyle;
|
|
else
|
|
instances.push_back(cellStyle);
|
|
}
|
|
|
|
text_format_properties_ptr textFormatProperties = calc_text_properties_content(instances);
|
|
paragraph_format_properties parFormatProperties = calc_paragraph_properties_content(instances);
|
|
style_table_cell_properties_attlist cellFormatProperties = calc_table_cell_properties(instances);
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
if (false == data_style.empty())
|
|
{
|
|
num_format = Context.get_num_format_context().find_complex_format(data_style, num_format_type);
|
|
|
|
if (num_format.empty())
|
|
{
|
|
office_element_ptr elm = odfContext.numberStyles().find_by_style_name(data_style);
|
|
number_style_base* num_style = dynamic_cast<number_style_base*>(elm.get());
|
|
|
|
if (num_style)
|
|
{
|
|
Context.get_num_format_context().start_complex_format(data_style);
|
|
num_style->oox_convert(Context.get_num_format_context());
|
|
Context.get_num_format_context().end_complex_format();
|
|
|
|
num_format = Context.get_num_format_context().get_last_format();
|
|
num_format_type = Context.get_num_format_context().type();
|
|
}
|
|
}
|
|
if (attr.office_value_type_)
|
|
{
|
|
if (attr.office_value_type_.get() != num_format_type && num_format_type != office_value_type::Custom)
|
|
{// reset from cell
|
|
num_format_type = attr.office_value_type_->get_type();
|
|
num_format.clear();
|
|
}
|
|
|
|
}
|
|
}
|
|
//----------------------------------------------------------------------------------------------------------------------------------
|
|
bool is_style_visible = (!cellStyleName.empty() || defaultColumnCellStyle || !num_format.empty()) ? true : false;
|
|
|
|
if (count_paragraph > 1)
|
|
{
|
|
is_style_visible = true;
|
|
cellFormatProperties.fo_wrap_option_ = odf_types::wrap_option::Wrap;
|
|
}
|
|
if (bExternalTable)
|
|
{
|
|
is_style_visible = false;
|
|
xlsx_value_type = oox::XlsxCellType::str;
|
|
}
|
|
oox::xlsx_cell_format cellFormat;
|
|
cellFormat.set_cell_type(xlsx_value_type);
|
|
cellFormat.set_num_format(oox::odf_string_to_build_in(odf_value_type));
|
|
|
|
size_t xfId_last_set = 0;
|
|
if (is_style_visible)
|
|
{
|
|
xfId_last_set = Context.get_style_manager().xfId(textFormatProperties, &parFormatProperties, &cellFormatProperties,
|
|
&cellFormat, num_format, num_format_type, false, is_style_visible);
|
|
}
|
|
if (cellStyle && cellStyle->content() && false == cellStyle->content()->style_map_.empty())
|
|
{
|
|
std::wstring ref = oox::getCellAddress(Context.current_table_column() + 1, Context.current_table_row());
|
|
|
|
if (attlist_.table_number_columns_repeated_ > 1)
|
|
{
|
|
ref += L":" + oox::getCellAddress(Context.current_table_column() + attlist_.table_number_columns_repeated_, Context.current_table_row());
|
|
}
|
|
std::wstring base_cell;
|
|
for (const auto& s_map : cellStyle->content()->style_map_)
|
|
{
|
|
if (const style_map* styleMap = dynamic_cast<const style_map*>(s_map.get()))
|
|
{
|
|
base_cell = styleMap->style_base_cell_address_;
|
|
break;
|
|
}
|
|
}
|
|
if (Context.get_conditionalFormatting_context().start_by(base_cell, ref))
|
|
{//odf 1.0
|
|
for (const auto& s_map : cellStyle->content()->style_map_)
|
|
{
|
|
if (const style_map* styleMap = dynamic_cast<const style_map*>(s_map.get()))
|
|
{
|
|
const std::wstring& applyStyleName = styleMap->style_apply_style_name_;
|
|
const std::wstring& condition = styleMap->style_condition_;
|
|
|
|
Context.get_conditionalFormatting_context().add_rule(1);
|
|
Context.get_conditionalFormatting_context().set_formula(condition);
|
|
|
|
int dxfId = Context.get_dxfId_style(applyStyleName);
|
|
|
|
if (dxfId >= 0)
|
|
Context.get_conditionalFormatting_context().set_dxf(dxfId);
|
|
}
|
|
}
|
|
Context.get_conditionalFormatting_context().end();
|
|
}
|
|
}
|
|
for (unsigned int r = 0; r < attlist_.table_number_columns_repeated_; ++r)
|
|
{
|
|
Context.start_table_cell ( attlist_extra_.table_number_columns_spanned_ - 1 ,
|
|
attlist_extra_.table_number_rows_spanned_ - 1 );
|
|
if (is_style_visible)
|
|
Context.set_current_cell_style_id(xfId_last_set);
|
|
//---------------------------------------------------------------------------------------------------------
|
|
if (bExternalTable)
|
|
{
|
|
std::wstringstream str;
|
|
content_.text_to_stream(str);
|
|
str_val = str.str();
|
|
}
|
|
else
|
|
{
|
|
sharedStringId = content_.xlsx_convert(Context, textFormatProperties, need_cache_convert);
|
|
}
|
|
|
|
if (xlsx_value_type == oox::XlsxCellType::str || xlsx_value_type == oox::XlsxCellType::inlineStr)
|
|
{
|
|
int index = Context.get_table_context().in_database_range();
|
|
|
|
if (index >= 0)
|
|
{
|
|
if (sharedStringId >= 0)
|
|
{
|
|
std::wstringstream strm;
|
|
content_.text_to_stream(strm);
|
|
|
|
Context.get_table_context().set_database_range_value(index, strm.str());
|
|
}
|
|
else if (str_val)
|
|
{
|
|
Context.get_table_context().set_database_range_value(index, str_val.get());
|
|
}
|
|
}
|
|
}
|
|
if (sharedStringId >= 0)
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::s;//for text, if it exists, we take the cached value
|
|
}
|
|
//---------------------------------------------------------------------------------------------------------
|
|
if (skip_next_cell)
|
|
{
|
|
Context.end_table_cell();
|
|
break;
|
|
}
|
|
|
|
// skip empty cells.
|
|
if ( is_data_visible || ((cellStyle || defaultColumnCellStyle) && is_style_visible))
|
|
{
|
|
std::wstring ref = oox::getCellAddress(Context.current_table_column(), Context.current_table_row());
|
|
if (attlist_.table_content_validation_name_)
|
|
{
|
|
Context.get_dataValidations_context().activate(*attlist_.table_content_validation_name_, /*ref*/Context.current_table_column(), Context.current_table_row());
|
|
}
|
|
CP_XML_WRITER(strm)
|
|
{
|
|
CP_XML_NODE(bExternalTable ? L"cell" : L"c")
|
|
{
|
|
CP_XML_ATTR(L"r", ref);
|
|
|
|
if (false == bExternalTable)
|
|
{
|
|
CP_XML_ATTR(L"s", xfId_last_set);
|
|
}
|
|
|
|
std::wstring type = oox::cellType2Str(xlsx_value_type);
|
|
if (false == type.empty()) CP_XML_ATTR(L"t", type);
|
|
|
|
if (false == bExternalTable && false == formula.empty())
|
|
{
|
|
const std::wstring xlsxFormula = formulas_converter.convert(formula);
|
|
if (!xlsxFormula.empty())
|
|
{
|
|
CP_XML_NODE(L"f")
|
|
{
|
|
if (attlist_extra_.table_number_matrix_columns_spanned_ && attlist_extra_.table_number_matrix_rows_spanned_)
|
|
{
|
|
std::wstring ref = oox::getCellAddress(Context.current_table_column(), Context.current_table_row());
|
|
ref += L":";
|
|
ref += oox::getCellAddress(Context.current_table_column() + *attlist_extra_.table_number_matrix_columns_spanned_ - 1,
|
|
Context.current_table_row() + *attlist_extra_.table_number_matrix_rows_spanned_ - 1);
|
|
CP_XML_ATTR(L"ref", ref);
|
|
CP_XML_ATTR(L"t", L"array");
|
|
CP_XML_ATTR(L"aca", false);
|
|
}
|
|
CP_XML_CONTENT(XmlUtils::EncodeXmlString(xlsxFormula));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sharedStringId >= 0 && xlsx_value_type == oox::XlsxCellType::s)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(sharedStringId); }
|
|
}
|
|
else if ((xlsx_value_type == oox::XlsxCellType::str || xlsx_value_type == oox::XlsxCellType::inlineStr) && str_val)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(XmlUtils::EncodeXmlString(str_val.get())); }
|
|
}
|
|
else if (!number_val.empty())
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(number_val);}
|
|
}
|
|
else if (xlsx_value_type == oox::XlsxCellType::b && bool_val)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT((int)(bool_val.get())); }
|
|
}
|
|
|
|
}
|
|
if ( is_data_visible || (cellStyle && is_style_visible && !last_cell_))
|
|
{
|
|
Context.get_table_context().state()->non_empty_row();
|
|
empty_cell_count = 0 ;
|
|
}
|
|
else
|
|
{
|
|
empty_cell_count++;
|
|
//Notification_of_delivery.ods - 13 empty repeats with cellStyle=NULL - needed!!!
|
|
if (empty_cell_count > 19 && last_cell_&& (attlist_.table_number_columns_repeated_> 299 || cellStyle == NULL))
|
|
{//write full sheet only if style is set only for these cells
|
|
skip_next_cell = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (last_cell_) // Vehicle log book.ods (row = 24 and more)
|
|
skip_next_cell = true;
|
|
}
|
|
|
|
Context.end_table_cell();
|
|
}
|
|
}
|
|
|
|
void table_covered_table_cell::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
bool bExternalTable = !Context.current_sheet().external_ref().empty();
|
|
|
|
std::wostream & strm = Context.current_sheet().sheetData();
|
|
|
|
const common_value_and_type_attlist & attr = attlist_.common_value_and_type_attlist_;
|
|
|
|
office_value_type::type odf_value_type = office_value_type::Custom;
|
|
oox::XlsxCellType::type xlsx_value_type = oox::XlsxCellType::s;
|
|
std::wstring formula = attlist_.table_formula_.get_value_or(L"");
|
|
|
|
std::wstring number_val;
|
|
_CP_OPT(bool) bool_val;
|
|
_CP_OPT(std::wstring) str_val;
|
|
|
|
std::wstring num_format;
|
|
|
|
size_t xfId_last_set = 0;
|
|
int empty_cell_count = 0;
|
|
bool skip_next_cell = false;
|
|
bool is_style_visible = true;
|
|
bool is_data_visible = false;
|
|
// calculate style for cell
|
|
|
|
std::wstring cellStyleName = attlist_.table_style_name_.get_value_or(L"");
|
|
std::wstring columnStyleName = Context.get_table_context().default_column_cell_style();
|
|
std::wstring rowStyleName = Context.get_table_context().default_row_cell_style();
|
|
|
|
if (attlist_.table_number_columns_repeated_ > 1)
|
|
columnStyleName.clear(); // there can be different column styles Book 24.ods
|
|
|
|
odf_read_context & odfContext = Context.root()->odf_context();
|
|
|
|
style_instance *defaultCellStyle=NULL, *defaultColumnCellStyle = NULL, *defaultRowCellStyle =NULL, *cellStyle = NULL;
|
|
try
|
|
{
|
|
defaultCellStyle = odfContext.styleContainer().style_default_by_type(style_family::TableCell);
|
|
|
|
defaultColumnCellStyle = odfContext.styleContainer().style_by_name(columnStyleName, style_family::TableCell, false);
|
|
defaultRowCellStyle = odfContext.styleContainer().style_by_name(rowStyleName, style_family::TableCell, false);
|
|
cellStyle = odfContext.styleContainer().style_by_name(cellStyleName, style_family::TableCell, false);
|
|
}
|
|
catch(...)
|
|
{
|
|
_CP_LOG << L"[error]: style wrong\n";
|
|
}
|
|
|
|
std::wstring data_style = CalcCellDataStyle(Context, columnStyleName, rowStyleName, cellStyleName);
|
|
|
|
// styles are not inherited
|
|
std::vector<const style_instance *> instances;
|
|
instances.push_back(defaultCellStyle);
|
|
|
|
if (defaultColumnCellStyle)
|
|
instances.push_back(defaultColumnCellStyle);
|
|
|
|
if (defaultRowCellStyle)
|
|
{
|
|
if (instances.size() > 1)
|
|
instances[1] = defaultRowCellStyle;
|
|
else
|
|
instances.push_back(defaultRowCellStyle);
|
|
}
|
|
|
|
if (cellStyle)
|
|
{
|
|
if (instances.size() > 1)
|
|
instances[1] = cellStyle;
|
|
else
|
|
instances.push_back(cellStyle);
|
|
}
|
|
|
|
text_format_properties_ptr textFormatProperties = calc_text_properties_content (instances);
|
|
paragraph_format_properties parFormatProperties = calc_paragraph_properties_content (instances);
|
|
style_table_cell_properties_attlist cellFormatProperties = calc_table_cell_properties (instances);
|
|
|
|
if (attr.office_value_type_)
|
|
odf_value_type = attr.office_value_type_->get_type();
|
|
|
|
if ((odf_value_type == office_value_type::Float) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
}
|
|
else if (odf_value_type == office_value_type::Percentage)
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
}
|
|
else if (odf_value_type == office_value_type::Currency)
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
number_val = attr.office_value_.get_value_or(L"");
|
|
}
|
|
else if ((odf_value_type == office_value_type::Date) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_date_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
if (attr.office_date_value_)
|
|
{
|
|
int y, m, d;
|
|
_CP_OPT(int) h, min, s;
|
|
if (oox::parseDateTime(attr.office_date_value_.get(), y, m, d, h, min, s))
|
|
{
|
|
boost::int64_t intDate = oox::convertDate(y, m, d);
|
|
_CP_OPT(double) dTime;
|
|
|
|
if (h && min)
|
|
{
|
|
dTime = oox::convertTime(*h, *min, s.get_value_or(0));
|
|
}
|
|
if (intDate > 0)
|
|
{
|
|
if (dTime)
|
|
{
|
|
number_val = XmlUtils::ToString(*dTime + intDate);
|
|
}
|
|
else
|
|
{
|
|
number_val = std::to_wstring(intDate);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
str_val = attr.office_date_value_.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ((odf_value_type == office_value_type::Time) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_time_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::n;
|
|
if (attr.office_time_value_)
|
|
{
|
|
const std::wstring tv = attr.office_time_value_.get();
|
|
int h,m;
|
|
double s;
|
|
if (oox::parseTime(tv, h, m, s))
|
|
{
|
|
number_val = boost::lexical_cast<std::wstring>(oox::convertTime(h, m, s));
|
|
}
|
|
}
|
|
}
|
|
else if ((odf_value_type == office_value_type::Boolean) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_boolean_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::b;
|
|
if (attr.office_boolean_value_) bool_val = oox::parseBoolVal(attr.office_boolean_value_.get());
|
|
}
|
|
else if ((odf_value_type == office_value_type::String) ||
|
|
(odf_value_type == office_value_type::Custom && attr.office_string_value_))
|
|
{
|
|
xlsx_value_type = oox::XlsxCellType::str;
|
|
if (attr.office_string_value_) str_val = attr.office_string_value_.get();
|
|
}
|
|
|
|
if (!data_style.empty())
|
|
{
|
|
num_format = Context.get_num_format_context().find_complex_format(data_style, odf_value_type);
|
|
|
|
if (num_format.empty())
|
|
{
|
|
office_element_ptr elm = odfContext.numberStyles().find_by_style_name(data_style);
|
|
number_style_base *num_style = dynamic_cast<number_style_base*>(elm.get());
|
|
|
|
if (num_style)
|
|
{
|
|
Context.get_num_format_context().start_complex_format(data_style);
|
|
num_style->oox_convert(Context.get_num_format_context());
|
|
Context.get_num_format_context().end_complex_format();
|
|
|
|
num_format = Context.get_num_format_context().get_last_format();
|
|
}
|
|
}
|
|
}
|
|
is_style_visible = (!cellStyleName.empty() || defaultColumnCellStyle) ? true : false;
|
|
|
|
if (bExternalTable)
|
|
{
|
|
is_style_visible = false;
|
|
xlsx_value_type = oox::XlsxCellType::inlineStr;
|
|
}
|
|
|
|
oox::xlsx_cell_format cellFormat;
|
|
cellFormat.set_cell_type(xlsx_value_type);
|
|
cellFormat.set_num_format(oox::odf_string_to_build_in(odf_value_type));
|
|
|
|
if ( content_.elements_.size() > 0 || attlist_.table_content_validation_name_ ||
|
|
!formula.empty() ||
|
|
( xlsx_value_type == oox::XlsxCellType::n && !number_val.empty()) ||
|
|
( xlsx_value_type == oox::XlsxCellType::b && bool_val) ||
|
|
(( xlsx_value_type == oox::XlsxCellType::str || oox::XlsxCellType::inlineStr) && str_val)) is_data_visible = true;
|
|
|
|
if (attlist_.table_number_columns_repeated_ < 199 && last_cell_) last_cell_ = false;
|
|
|
|
int cell_repeated_max = Context.current_table_column() + attlist_.table_number_columns_repeated_ + 1;
|
|
|
|
if (cell_repeated_max >= 1024 && cellStyleName.empty() && last_cell_ && !is_data_visible)
|
|
{//Book 24.ods
|
|
return;
|
|
}
|
|
|
|
if (is_style_visible)
|
|
{
|
|
xfId_last_set = Context.get_style_manager().xfId(textFormatProperties, &parFormatProperties, &cellFormatProperties, &cellFormat, num_format, false, is_style_visible);
|
|
}
|
|
|
|
for (unsigned int r = 0; r < attlist_.table_number_columns_repeated_; ++r)
|
|
{
|
|
Context.start_table_covered_cell ();
|
|
|
|
if (attlist_.table_content_validation_name_)
|
|
{
|
|
Context.get_dataValidations_context().activate(*attlist_.table_content_validation_name_, /*ref*/Context.current_table_column(), Context.current_table_row());
|
|
}
|
|
if (is_style_visible)
|
|
Context.set_current_cell_style_id(xfId_last_set);
|
|
|
|
const int sharedStringId = content_.xlsx_convert(Context, textFormatProperties);
|
|
|
|
if (xlsx_value_type == oox::XlsxCellType::str && sharedStringId >= 0)
|
|
xlsx_value_type = oox::XlsxCellType::s;//for text, if it exists, we take the cached value
|
|
|
|
if (skip_next_cell) break;
|
|
|
|
// skip empty cells.
|
|
if ( is_data_visible || ((cellStyle || defaultColumnCellStyle) && is_style_visible))
|
|
{
|
|
CP_XML_WRITER(strm)
|
|
{
|
|
CP_XML_NODE(L"c")
|
|
{
|
|
CP_XML_ATTR(L"r", oox::getCellAddress(Context.current_table_column(), Context.current_table_row()));
|
|
|
|
std::wstring type = oox::cellType2Str(xlsx_value_type);
|
|
if (false == type.empty()) CP_XML_ATTR(L"t", type);
|
|
|
|
CP_XML_ATTR(L"s", xfId_last_set);
|
|
|
|
if (!formula.empty())
|
|
{
|
|
const std::wstring xlsxFormula = formulas_converter.convert(formula);
|
|
if (!xlsxFormula.empty())
|
|
{
|
|
CP_XML_NODE(L"f")
|
|
{
|
|
CP_XML_CONTENT(xlsxFormula);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sharedStringId >= 0 && xlsx_value_type == oox::XlsxCellType::s)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(sharedStringId); }
|
|
}
|
|
else if ((xlsx_value_type == oox::XlsxCellType::str || xlsx_value_type == oox::XlsxCellType::inlineStr) && str_val)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(str_val.get()); }
|
|
}
|
|
else if (xlsx_value_type == oox::XlsxCellType::n && !number_val.empty())
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT(number_val);}
|
|
}
|
|
else if (xlsx_value_type == oox::XlsxCellType::b && bool_val)
|
|
{
|
|
CP_XML_NODE(L"v") { CP_XML_CONTENT((int)(bool_val.get())); }
|
|
}
|
|
}
|
|
if ( is_data_visible || (cellStyle && is_style_visible && !last_cell_))
|
|
{
|
|
Context.get_table_context().state()->non_empty_row();
|
|
empty_cell_count = 0 ;
|
|
}
|
|
else
|
|
{
|
|
empty_cell_count++;
|
|
//Notification_of_delivery.ods - 13 empty repeats with cellStyle=NULL - needed!!!
|
|
if (empty_cell_count > 19 && last_cell_&& (attlist_.table_number_columns_repeated_> 299 || cellStyle == NULL))
|
|
{//write full sheet only if style is set only for these cells
|
|
skip_next_cell = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (last_cell_) // Vehicle log book.ods (row = 24 and more)
|
|
skip_next_cell = true;
|
|
}
|
|
|
|
Context.end_table_covered_cell();
|
|
}
|
|
}
|
|
|
|
void table_content_validations::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
for (size_t i = 0 ; i < content_.size(); i++)
|
|
{
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
void table_content_validation::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
std::wstring name = table_name_.get_value_or(L"");
|
|
|
|
Context.get_dataValidations_context().add(name, table_base_cell_address_.get_value_or(L""));
|
|
Context.get_dataValidations_context().add_formula(name, table_condition_.get_value_or(L""));
|
|
|
|
for (size_t i = 0 ; i < content_.size(); i++)
|
|
{
|
|
if (content_[i]->get_type() == typeTableErrorMassage)
|
|
{
|
|
table_error_message* error = dynamic_cast<table_error_message*>(content_[i].get());
|
|
|
|
Context.get_text_context()->start_only_text();
|
|
for (size_t j = 0 ; j < error->content_.size(); j++)
|
|
{
|
|
error->content_[j]->xlsx_convert(Context);
|
|
}
|
|
std::wstring content = Context.get_text_context()->end_only_text();
|
|
|
|
Context.get_dataValidations_context().add_error_msg(name, error->table_title_.get_value_or(L""), content,
|
|
error->table_display_ ? error->table_display_->get() : true,
|
|
error->table_message_type_.get_value_or(message_type::stop).get_type());
|
|
}
|
|
else if (content_[i]->get_type() == typeTableHelpMassage)
|
|
{
|
|
table_help_message* help = dynamic_cast<table_help_message*>(content_[i].get());
|
|
|
|
Context.get_text_context()->start_only_text();
|
|
for (size_t j = 0 ; j < help->content_.size(); j++)
|
|
{
|
|
help->content_[j]->xlsx_convert(Context);
|
|
}
|
|
std::wstring content = Context.get_text_context()->end_only_text();
|
|
|
|
Context.get_dataValidations_context().add_help_msg(name, help->table_title_.get_value_or(L""), content,
|
|
help->table_display_ ? help->table_display_->get() : true);
|
|
}
|
|
content_[i]->xlsx_convert(Context);
|
|
}
|
|
}
|
|
void table_error_message::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
}
|
|
void table_help_message::xlsx_convert(oox::xlsx_conversion_context & Context)
|
|
{
|
|
}
|
|
}
|
|
}
|