mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
502 lines
16 KiB
C++
502 lines
16 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 "xlsx_conversion_context.h"
|
|
|
|
#include <iostream>
|
|
#include "../../Common/Utils/simple_xml_writer.h"
|
|
|
|
#include "xlsx_package.h"
|
|
|
|
|
|
namespace oox {
|
|
|
|
|
|
xlsx_conversion_context::xlsx_conversion_context( package::xlsx_document * outputDocument) : output_document_(outputDocument),
|
|
next_vml_file_id_ ( 1 ),
|
|
sheet_context_ ( *this ),
|
|
xlsx_drawing_context_handle_ ( next_vml_file_id_, get_mediaitems())
|
|
{
|
|
}
|
|
xlsx_conversion_context::~xlsx_conversion_context()
|
|
{
|
|
}
|
|
|
|
xlsx_comments_context & xlsx_conversion_context::get_comments_context()
|
|
{
|
|
return get_sheet_context().get_comments_context();
|
|
}
|
|
|
|
xlsx_comments_context_handle & xlsx_conversion_context::get_comments_context_handle()
|
|
{
|
|
return xlsx_comments_context_handle_;
|
|
}
|
|
|
|
xlsx_drawing_context & xlsx_conversion_context::get_drawing_context()
|
|
{
|
|
return get_sheet_context().get_drawing_context();
|
|
}
|
|
|
|
void xlsx_conversion_context::start_document()
|
|
{
|
|
}
|
|
|
|
xlsx_xml_worksheet & xlsx_conversion_context::current_sheet()
|
|
{
|
|
if (!sheets_.empty())
|
|
{
|
|
return *sheets_.back().get();
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("internal error");
|
|
}
|
|
}
|
|
|
|
oox_chart_context & xlsx_conversion_context::current_chart()
|
|
{
|
|
if (!charts_.empty())
|
|
{
|
|
return *charts_.back().get();
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("internal error");
|
|
}
|
|
}
|
|
oox_external_context & xlsx_conversion_context::current_external()
|
|
{
|
|
if (!externals_.empty())
|
|
{
|
|
return *externals_.back().get();
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("internal error");
|
|
}
|
|
}
|
|
oox_activeX_context & xlsx_conversion_context::current_activeX()
|
|
{
|
|
if (!activeXs_.empty())
|
|
{
|
|
return *activeXs_.back().get();
|
|
}
|
|
else
|
|
{
|
|
throw std::runtime_error("internal error");
|
|
}
|
|
}
|
|
bool xlsx_conversion_context::start_sheet()
|
|
{
|
|
sheets_.push_back(xlsx_xml_worksheet::create());
|
|
get_sheet_context().start_table();
|
|
|
|
return true;
|
|
}
|
|
|
|
void xlsx_conversion_context::set_sheet_type(int type)
|
|
{
|
|
if (sheets_.empty()) return;
|
|
|
|
sheets_.back()->type = type;
|
|
}
|
|
void xlsx_conversion_context::start_table()
|
|
{
|
|
}
|
|
void xlsx_conversion_context::end_table()
|
|
{
|
|
int index = tables_context_.get_count();
|
|
|
|
std::wstring rid = L"tpId" + std::to_wstring(index);
|
|
|
|
current_sheet().sheet_rels().add(oox::relationship(rid,
|
|
L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
|
|
L"../tables/table" + std::to_wstring(index) +L".xml"));
|
|
|
|
CP_XML_WRITER(current_sheet().tableParts())
|
|
{
|
|
CP_XML_NODE(L"tablePart")
|
|
{
|
|
CP_XML_ATTR(L"r:id", rid);
|
|
}
|
|
}
|
|
}
|
|
void xlsx_conversion_context::set_sheet_name(const std::wstring & name)
|
|
{
|
|
if (name.empty()) return;
|
|
|
|
sheets_.back()->name = name;
|
|
}
|
|
void xlsx_conversion_context::set_sheet_state(const std::wstring & state)
|
|
{
|
|
if (state.empty()) return;
|
|
|
|
sheets_.back()->state = state;
|
|
}
|
|
void xlsx_conversion_context::set_sheet_id(int id)
|
|
{
|
|
if (id < 0) return;
|
|
sheets_.back()->id = id;
|
|
|
|
sheets_map_.insert(std::make_pair(id, sheets_.size() - 1));
|
|
}
|
|
void xlsx_conversion_context::start_chart()
|
|
{
|
|
charts_.push_back(oox_chart_context::create());
|
|
//добавляем новую форму для диаграммы
|
|
//в ней будет информационная часть - и она пишется каждый раз в свою xml (их - по числу диаграмм)
|
|
//этот контекст нужно передавать в файл
|
|
|
|
}
|
|
|
|
std::wstring xlsx_conversion_context::start_activeX()
|
|
{
|
|
activeXs_.push_back(oox_activeX_context::create());
|
|
|
|
size_t index = activeXs_.size();
|
|
|
|
std::wstring rid = L"ocxId" + std::to_wstring(index);
|
|
|
|
current_sheet().sheet_rels().add(oox::relationship(rid,
|
|
L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/control",
|
|
L"../activeX/activeX" + std::to_wstring(index) +L".xml"));
|
|
|
|
return rid;
|
|
}
|
|
void xlsx_conversion_context::start_external()
|
|
{
|
|
externals_.push_back(oox_external_context::create());
|
|
}
|
|
void xlsx_conversion_context::end_external()
|
|
{
|
|
}
|
|
|
|
|
|
void xlsx_conversion_context::end_sheet()
|
|
{
|
|
get_sheet_context().serialize_ole_objects (current_sheet().ole_objects());
|
|
get_sheet_context().serialize_controls (current_sheet().activeXs());
|
|
|
|
get_sheet_context().dump_rels_drawing(current_sheet().sheet_rels());
|
|
|
|
get_sheet_context().serialize_hyperlinks(current_sheet().hyperlinks());
|
|
get_sheet_context().dump_rels_hyperlinks(current_sheet().sheet_rels());
|
|
|
|
get_sheet_context().end_table();
|
|
}
|
|
|
|
xlsx_drawing_context_handle & xlsx_conversion_context::get_drawing_context_handle()
|
|
{
|
|
return xlsx_drawing_context_handle_;
|
|
}
|
|
|
|
void xlsx_conversion_context::add_connections(const std::wstring & connections)
|
|
{
|
|
if (connections.empty()) return;
|
|
connections_ = connections;
|
|
}
|
|
|
|
void xlsx_conversion_context::add_query_table (const std::wstring & query_table)
|
|
{
|
|
if (query_table.empty()) return;
|
|
|
|
std::wstring rid = L"qtId" + std::to_wstring(query_tables_.size() + 1);
|
|
std::wstring target = L"queryTable" + std::to_wstring(query_tables_.size() + 1) + L".xml";
|
|
|
|
query_tables_.insert(std::make_pair(target, query_table));
|
|
|
|
current_sheet().sheet_rels().add(oox::relationship(rid,
|
|
L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/queryTable",
|
|
L"../queryTables/" + target));
|
|
|
|
}
|
|
|
|
void xlsx_conversion_context::add_control_props(const std::wstring & target, const std::wstring & props)
|
|
{
|
|
if (props.empty()) return;
|
|
control_props_.insert(std::make_pair(target, props));
|
|
}
|
|
|
|
void xlsx_conversion_context::end_document()
|
|
{
|
|
std::wstringstream workbook_content;
|
|
|
|
//for (size_t i = 0; i < sheets_.size(); i++) нужно по id
|
|
for (std::map<int, int>::iterator it = sheets_map_.begin(); it != sheets_map_.end(); ++it)
|
|
{
|
|
int i = it->second;
|
|
|
|
package::sheet_content_ptr content = package::sheet_content::create();
|
|
|
|
const std::wstring slideRId = std::wstring(L"sId") + std::to_wstring(i + 1);
|
|
content->set_rId(slideRId);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////
|
|
const std::pair<std::wstring, std::wstring> p1 = sheets_[i]->get_drawing_link();
|
|
|
|
if (!p1.first.empty())
|
|
{
|
|
const std::wstring dId = p1.second;
|
|
static const std::wstring kType = L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
|
|
const std::wstring dName = std::wstring(L"../drawings/" + p1.first);
|
|
content->add_rel(relationship(dId, kType, dName));
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
content->add_rels(sheets_[i]->sheet_rels());
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
const std::pair<std::wstring, std::wstring> p2 = sheets_[i]->get_comments_link();
|
|
if (!p2.first.empty())
|
|
{
|
|
const std::wstring dId = p2.second;
|
|
static const std::wstring kType = L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
|
|
const std::wstring dName = std::wstring(L"../" + p2.first);
|
|
content->add_rel(relationship(dId, kType, dName));
|
|
}
|
|
|
|
const std::pair<std::wstring, std::wstring> p3 = sheets_[i]->get_vml_drawing_link();
|
|
if (!p3.first.empty())
|
|
{
|
|
const std::wstring dId = p3.second;
|
|
static const std::wstring kType = L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
|
const std::wstring dName = std::wstring(L"../drawings/" + p3.first);
|
|
content->add_rel(relationship(dId, kType, dName));
|
|
}
|
|
|
|
const std::pair<std::wstring, std::wstring> p4 = sheets_[i]->get_vml_drawing_HF_link();
|
|
if (!p4.first.empty())
|
|
{
|
|
const std::wstring dId = p4.second;
|
|
static const std::wstring kType = L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing";
|
|
const std::wstring dName = std::wstring(L"../drawings/" + p4.first);
|
|
content->add_rel(relationship(dId, kType, dName));
|
|
}
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
sheets_[i]->write_to(content->content());
|
|
|
|
output_document_->get_xl_files().add_sheet(sheets_[i]->type, content);
|
|
|
|
/////////////////////////////////////////////
|
|
CP_XML_WRITER(workbook_content)
|
|
{
|
|
CP_XML_NODE(L"sheet")
|
|
{
|
|
CP_XML_ATTR(L"name", sheets_[i]->name);
|
|
CP_XML_ATTR(L"sheetId", sheets_[i]->id);
|
|
CP_XML_ATTR(L"state", sheets_[i]->state);
|
|
CP_XML_ATTR(L"r:id", slideRId);
|
|
}
|
|
}
|
|
|
|
}
|
|
unsigned int count = 0;
|
|
for (size_t i = 0; i < activeXs_.size(); i++)
|
|
{
|
|
package::activeX_content_ptr content = package::activeX_content::create();
|
|
|
|
activeXs_[i]->dump_rels(content->get_rels());
|
|
activeXs_[i]->write_to(content->content());
|
|
|
|
output_document_->get_xl_files().add_activeX(content);
|
|
}
|
|
for (size_t i = 0; i < charts_.size(); i++)
|
|
{
|
|
package::chart_content_ptr content = package::chart_content::create();
|
|
|
|
charts_[i]->dump_rels(content->get_rels());
|
|
charts_[i]->write_to(content->content());
|
|
|
|
output_document_->get_xl_files().add_chart(content);
|
|
}
|
|
if (!connections_.empty())
|
|
{
|
|
std::wstringstream strm;
|
|
CP_XML_WRITER(strm)
|
|
{
|
|
CP_XML_NODE(L"connections")
|
|
{
|
|
CP_XML_ATTR(L"xmlns", L"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
|
|
|
CP_XML_STREAM() << connections_;
|
|
}
|
|
}
|
|
output_document_->get_xl_files().set_connections( package::simple_element::create(L"connections.xml", strm.str()) );
|
|
}
|
|
for (std::map<std::wstring, std::wstring>::iterator it = query_tables_.begin(); it != query_tables_.end(); ++it)
|
|
{
|
|
output_document_->get_xl_files().add_query_table( package::simple_element::create(it->first, it->second) );
|
|
}
|
|
for (std::map<std::wstring, std::wstring>::iterator it = control_props_.begin(); it != control_props_.end(); ++it)
|
|
{
|
|
output_document_->get_xl_files().add_control_props( package::simple_element::create(it->first, it->second) );
|
|
}
|
|
//workbook_content << L"<calcPr iterateCount=\"100\" refMode=\"A1\" iterate=\"false\" iterateDelta=\"0.0001\" />";
|
|
|
|
output_document_->get_xl_files().set_sharedStrings( package::simple_element::create(L"sharedStrings.xml", xlsx_shared_strings_.str()) );
|
|
|
|
|
|
std::wstringstream strm_workbook;
|
|
|
|
CP_XML_WRITER(strm_workbook)
|
|
{
|
|
CP_XML_NODE(L"workbook")
|
|
{
|
|
CP_XML_ATTR(L"xmlns", L"http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
|
CP_XML_ATTR(L"xmlns:r", L"http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
|
CP_XML_ATTR(L"xmlns:mc", L"http://schemas.openxmlformats.org/markup-compatibility/2006");
|
|
CP_XML_ATTR(L"mc:Ignorable", L"x15");
|
|
CP_XML_ATTR(L"xmlns:x15", L"http://schemas.microsoft.com/office/spreadsheetml/2010/11/main");
|
|
|
|
CP_XML_STREAM() << xlsx_workbook_pr_.str();
|
|
|
|
CP_XML_STREAM() << xlsx_workbookProtection_.str();
|
|
|
|
std::wstring str_bookViews = xlsx_workbook_views_.str();
|
|
|
|
if (false == str_bookViews.empty())
|
|
{
|
|
CP_XML_NODE(L"bookViews")
|
|
{
|
|
CP_XML_STREAM() << str_bookViews;
|
|
}
|
|
}
|
|
CP_XML_NODE(L"sheets")
|
|
{
|
|
CP_XML_STREAM() << workbook_content.str();
|
|
}
|
|
if (externals_.empty() == false)
|
|
{
|
|
CP_XML_NODE(L"externalReferences")
|
|
{
|
|
for (size_t i = 0; i < externals_.size(); i++)
|
|
{
|
|
std::wstring rId = L"extId" + std::to_wstring(i+1);
|
|
|
|
CP_XML_NODE(L"externalReference")
|
|
{
|
|
CP_XML_ATTR(L"r:id", rId);
|
|
}
|
|
package::external_content_ptr content = package::external_content::create();
|
|
|
|
externals_[i]->dump_rels(content->get_rels());
|
|
externals_[i]->write_to(content->content());
|
|
|
|
output_document_->get_xl_files().add_external(content);
|
|
}
|
|
}
|
|
}
|
|
CP_XML_NODE(L"definedNames")
|
|
{
|
|
CP_XML_STREAM() << xlsx_defined_names_.str();
|
|
}
|
|
|
|
std::wstring str_ = xlsx_custom_views_.str();
|
|
|
|
if (!str_.empty())
|
|
{
|
|
CP_XML_NODE(L"customWorkbookViews")
|
|
{
|
|
CP_XML_STREAM() << str_;
|
|
}
|
|
}
|
|
int pivot_cache_count = pivots_context_.get_cache_count();
|
|
if (pivot_cache_count > 0)
|
|
{
|
|
CP_XML_NODE(L"pivotCaches")
|
|
{
|
|
for (int i = 0; i < pivot_cache_count; i++)
|
|
{
|
|
std::wstring rId = L"pcId" + std::to_wstring(i+1);
|
|
static const std::wstring sType = L"http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheDefinition";
|
|
const std::wstring sName = std::wstring(L"../pivotCache/pivotCacheDefinition" + std::to_wstring(i + 1) + L".xml");
|
|
|
|
package::pivot_cache_content_ptr content = package::pivot_cache_content::create();
|
|
|
|
CP_XML_NODE(L"pivotCache")
|
|
{
|
|
CP_XML_ATTR(L"cacheId", std::to_wstring(i));
|
|
CP_XML_ATTR(L"r:id", rId);
|
|
}
|
|
|
|
pivots_context_.dump_rels_cache(i, content->get_rels());
|
|
pivots_context_.write_cache_definitions_to(i, content->definitions());
|
|
pivots_context_.write_cache_records_to(i, content->records());
|
|
|
|
output_document_->get_xl_files().add_pivot_cache(content);
|
|
}
|
|
}
|
|
}
|
|
int pivot_view_count = pivots_context_.get_view_count();
|
|
if (pivot_view_count > 0)
|
|
{
|
|
for (int i = 0; i < pivot_view_count; i++)
|
|
{
|
|
package::pivot_table_content_ptr content = package::pivot_table_content::create();
|
|
|
|
pivots_context_.dump_rels_view(i, content->get_rels());
|
|
pivots_context_.write_table_view_to(i, content->content());
|
|
|
|
output_document_->get_xl_files().add_pivot_table(content);
|
|
}
|
|
}
|
|
|
|
}
|
|
int table_parts_count = tables_context_.get_count();
|
|
if (table_parts_count > 0)
|
|
{
|
|
for (int i = 0; i < table_parts_count; i++)
|
|
{
|
|
package::table_part_content_ptr content = package::table_part_content::create();
|
|
|
|
tables_context_.dump_rels(i, content->get_rels());
|
|
tables_context_.write_to(i, content->content());
|
|
|
|
output_document_->get_xl_files().add_table_part(content);
|
|
}
|
|
}
|
|
output_document_->get_xl_files().set_workbook( package::simple_element::create(L"workbook.xml", strm_workbook.str()) );
|
|
|
|
output_document_->content_type().set_media(get_mediaitems());
|
|
output_document_->get_xl_files().set_media(get_mediaitems());
|
|
|
|
package::xl_drawings_ptr drawings = package::xl_drawings::create(xlsx_drawing_context_handle_.content());
|
|
output_document_->get_xl_files().set_drawings(drawings);
|
|
|
|
package::xl_drawings_ptr drawings_vml = package::xl_drawings::create(xlsx_drawing_context_handle_.content_vml());
|
|
output_document_->get_xl_files().set_vml_drawings(drawings_vml);
|
|
|
|
package::xl_comments_ptr comments = package::xl_comments::create(xlsx_comments_context_handle_.content());
|
|
output_document_->get_xl_files().set_comments(comments);
|
|
}
|
|
}
|
|
|
|
}
|