implement app properties reading/writing, case-insenstive border enum->string conversions for some style enums

This commit is contained in:
Thomas Fussell 2016-03-09 11:32:32 +08:00
parent e7b062bb4c
commit 0c3a167f7c
8 changed files with 200 additions and 34 deletions

View File

@ -0,0 +1,48 @@
// Copyright (c) 2014-2016 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#pragma once
#include <string>
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
/// <summary>
/// High-level properties of the OOXML document regarding the app that created it.
/// </summary>
class XLNT_CLASS app_properties
{
public:
std::string application = "libxlnt";
int doc_security = 0;
bool scale_crop = false;
std::string company = "";
bool links_up_to_date = false;
bool shared_doc = false;
bool hyperlinks_changed = false;
std::string app_version = "0.9";
};
} // namespace xlnt

View File

@ -35,6 +35,7 @@
namespace xlnt { namespace xlnt {
class alignment; class alignment;
class app_properties;
class border; class border;
class color; class color;
class const_worksheet_iterator; class const_worksheet_iterator;
@ -136,6 +137,9 @@ public:
document_properties &get_properties(); document_properties &get_properties();
const document_properties &get_properties() const; const document_properties &get_properties() const;
app_properties &get_app_properties();
const app_properties &get_app_properties() const;
// named ranges // named ranges
std::vector<named_range> get_named_ranges() const; std::vector<named_range> get_named_ranges() const;
void create_named_range(const std::string &name, worksheet worksheet, const range_reference &reference); void create_named_range(const std::string &name, worksheet worksheet, const range_reference &reference);

View File

@ -40,6 +40,7 @@ struct workbook_impl
drawings_(other.drawings_), drawings_(other.drawings_),
shared_strings_(other.shared_strings_), shared_strings_(other.shared_strings_),
properties_(other.properties_), properties_(other.properties_),
app_properties_(other.app_properties_),
guess_types_(other.guess_types_), guess_types_(other.guess_types_),
data_only_(other.data_only_), data_only_(other.data_only_),
read_only_(other.read_only_), read_only_(other.read_only_),
@ -68,6 +69,7 @@ struct workbook_impl
shared_strings_.clear(); shared_strings_.clear();
std::copy(other.shared_strings_.begin(), other.shared_strings_.end(), std::back_inserter(shared_strings_)); std::copy(other.shared_strings_.begin(), other.shared_strings_.end(), std::back_inserter(shared_strings_));
properties_ = other.properties_; properties_ = other.properties_;
app_properties_ = other.app_properties_;
guess_types_ = other.guess_types_; guess_types_ = other.guess_types_;
data_only_ = other.data_only_; data_only_ = other.data_only_;
read_only_ = other.read_only_; read_only_ = other.read_only_;
@ -90,6 +92,7 @@ struct workbook_impl
std::vector<std::string> shared_strings_; std::vector<std::string> shared_strings_;
document_properties properties_; document_properties properties_;
app_properties app_properties_;
bool guess_types_; bool guess_types_;
bool data_only_; bool data_only_;

View File

@ -3,13 +3,14 @@
#include <iostream> #include <iostream>
#include <cxxtest/TestSuite.h> #include <cxxtest/TestSuite.h>
#include <xlnt/packaging/app_properties.hpp>
#include <xlnt/serialization/workbook_serializer.hpp> #include <xlnt/serialization/workbook_serializer.hpp>
#include <xlnt/serialization/xml_document.hpp> #include <xlnt/serialization/xml_document.hpp>
#include <helpers/path_helper.hpp> #include <helpers/path_helper.hpp>
#include <helpers/helper.hpp> #include <helpers/helper.hpp>
class test_props : public CxxTest::TestSuite class test_core : public CxxTest::TestSuite
{ {
public: public:
void test_read_properties_core() void test_read_properties_core()
@ -86,6 +87,8 @@ public:
void test_write_properties_app() void test_write_properties_app()
{ {
xlnt::workbook wb; xlnt::workbook wb;
wb.get_app_properties().application = "Microsoft Excel";
wb.get_app_properties().app_version = "12.0000";
wb.create_sheet(); wb.create_sheet();
wb.create_sheet(); wb.create_sheet();
xlnt::workbook_serializer serializer(wb); xlnt::workbook_serializer serializer(wb);

View File

@ -94,6 +94,14 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
workbook_serializer_.read_properties_core(core_properties_xml); workbook_serializer_.read_properties_core(core_properties_xml);
} }
if(archive.has_file(xlnt::constants::ArcApp()))
{
xlnt::workbook_serializer workbook_serializer_(wb);
xlnt::xml_document app_properties_xml;
app_properties_xml.from_string(archive.read(xlnt::constants::ArcApp()));
workbook_serializer_.read_properties_app(app_properties_xml);
}
xlnt::relationship_serializer relationship_serializer_(archive); xlnt::relationship_serializer relationship_serializer_(archive);
auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::ArcWorkbook()); auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::ArcWorkbook());

View File

@ -34,6 +34,24 @@
namespace { namespace {
bool equals_case_insensitive(const std::string &left, const std::string &right)
{
if (left.size() != right.size())
{
return false;
}
for (std::size_t i = 0; i < left.size(); i++)
{
if (std::tolower(left[i]) != std::tolower(right[i]))
{
return false;
}
}
return true;
}
bool is_true(const std::string &bool_string) bool is_true(const std::string &bool_string)
{ {
return bool_string == "1"; return bool_string == "1";
@ -41,11 +59,11 @@ bool is_true(const std::string &bool_string)
xlnt::protection::type protection_type_from_string(const std::string &type_string) xlnt::protection::type protection_type_from_string(const std::string &type_string)
{ {
if (type_string == "true") if (equals_case_insensitive(type_string, "true"))
{ {
return xlnt::protection::type::protected_; return xlnt::protection::type::protected_;
} }
else if (type_string == "inherit") else if (equals_case_insensitive(type_string, "inherit"))
{ {
return xlnt::protection::type::inherit; return xlnt::protection::type::inherit;
} }
@ -55,23 +73,23 @@ xlnt::protection::type protection_type_from_string(const std::string &type_strin
xlnt::font::underline_style underline_style_from_string(const std::string &underline_string) xlnt::font::underline_style underline_style_from_string(const std::string &underline_string)
{ {
if (underline_string == "none") if (equals_case_insensitive(underline_string, "none"))
{ {
return xlnt::font::underline_style::none; return xlnt::font::underline_style::none;
} }
else if (underline_string == "single") else if (equals_case_insensitive(underline_string, "single"))
{ {
return xlnt::font::underline_style::single; return xlnt::font::underline_style::single;
} }
else if (underline_string == "single-accounting") else if (equals_case_insensitive(underline_string, "single-accounting"))
{ {
return xlnt::font::underline_style::single_accounting; return xlnt::font::underline_style::single_accounting;
} }
else if (underline_string == "double") else if (equals_case_insensitive(underline_string, "double"))
{ {
return xlnt::font::underline_style::double_; return xlnt::font::underline_style::double_;
} }
else if (underline_string == "double-accounting") else if (equals_case_insensitive(underline_string, "double-accounting"))
{ {
return xlnt::font::underline_style::double_accounting; return xlnt::font::underline_style::double_accounting;
} }
@ -81,73 +99,75 @@ xlnt::font::underline_style underline_style_from_string(const std::string &under
xlnt::fill::pattern_type pattern_fill_type_from_string(const std::string &fill_type) xlnt::fill::pattern_type pattern_fill_type_from_string(const std::string &fill_type)
{ {
if (fill_type == "none") return xlnt::fill::pattern_type::none; if (equals_case_insensitive(fill_type, "none")) return xlnt::fill::pattern_type::none;
if (fill_type == "solid") return xlnt::fill::pattern_type::solid; if (equals_case_insensitive(fill_type, "solid")) return xlnt::fill::pattern_type::solid;
if (fill_type == "gray125") return xlnt::fill::pattern_type::gray125; if (equals_case_insensitive(fill_type, "gray125")) return xlnt::fill::pattern_type::gray125;
return xlnt::fill::pattern_type::none; return xlnt::fill::pattern_type::none;
}; };
xlnt::border_style border_style_from_string(const std::string &border_style_string) xlnt::border_style border_style_from_string(const std::string &border_style_string)
{ {
if (border_style_string == "none") if (equals_case_insensitive(border_style_string, "none"))
{ {
return xlnt::border_style::none; return xlnt::border_style::none;
} }
else if (border_style_string == "dashdot") else if (equals_case_insensitive(border_style_string, "dashdot"))
{ {
return xlnt::border_style::dashdot; return xlnt::border_style::dashdot;
} }
else if (border_style_string == "dashdotdot") else if (equals_case_insensitive(border_style_string, "dashdotdot"))
{ {
return xlnt::border_style::dashdotdot; return xlnt::border_style::dashdotdot;
} }
else if (border_style_string == "dashed") else if (equals_case_insensitive(border_style_string, "dashed"))
{ {
return xlnt::border_style::dashed; return xlnt::border_style::dashed;
} }
else if (border_style_string == "dotted") else if (equals_case_insensitive(border_style_string, "dotted"))
{ {
return xlnt::border_style::dotted; return xlnt::border_style::dotted;
} }
else if (border_style_string == "double") else if (equals_case_insensitive(border_style_string, "double"))
{ {
return xlnt::border_style::double_; return xlnt::border_style::double_;
} }
else if (border_style_string == "hair") else if (equals_case_insensitive(border_style_string, "hair"))
{ {
return xlnt::border_style::hair; return xlnt::border_style::hair;
} }
else if (border_style_string == "medium") else if (equals_case_insensitive(border_style_string, "medium"))
{ {
return xlnt::border_style::medium; return xlnt::border_style::medium;
} }
else if (border_style_string == "mediumdashdot") else if (equals_case_insensitive(border_style_string, "mediumdashdot"))
{ {
return xlnt::border_style::mediumdashdot; return xlnt::border_style::mediumdashdot;
} }
else if (border_style_string == "mediumdashdotdot") else if (equals_case_insensitive(border_style_string, "mediumdashdotdot"))
{ {
return xlnt::border_style::mediumdashdotdot; return xlnt::border_style::mediumdashdotdot;
} }
else if (border_style_string == "mediumdashed") else if (equals_case_insensitive(border_style_string, "mediumdashed"))
{ {
return xlnt::border_style::mediumdashed; return xlnt::border_style::mediumdashed;
} }
else if (border_style_string == "slantdashdot") else if (equals_case_insensitive(border_style_string, "slantdashdot"))
{ {
return xlnt::border_style::slantdashdot; return xlnt::border_style::slantdashdot;
} }
else if (border_style_string == "thick") else if (equals_case_insensitive(border_style_string, "thick"))
{ {
return xlnt::border_style::thick; return xlnt::border_style::thick;
} }
else if (border_style_string == "thin") else if (equals_case_insensitive(border_style_string, "thin"))
{ {
return xlnt::border_style::thin; return xlnt::border_style::thin;
} }
else else
{ {
throw std::runtime_error("unknown border style"); std::string message = "unknown border style: ";
message.append(border_style_string);
throw std::runtime_error(border_style_string);
} }
} }
@ -696,6 +716,9 @@ xml_document style_serializer::write_stylesheet() const
case color::type::indexed: case color::type::indexed:
fg_color_node.add_attribute("indexed", std::to_string(fill_.get_foreground_color()->get_index())); fg_color_node.add_attribute("indexed", std::to_string(fill_.get_foreground_color()->get_index()));
break; break;
case color::type::rgb:
fg_color_node.add_attribute("rgb", fill_.get_foreground_color()->get_rgb_string());
break;
default: default:
throw std::runtime_error("bad type"); throw std::runtime_error("bad type");
} }
@ -716,6 +739,9 @@ xml_document style_serializer::write_stylesheet() const
case color::type::indexed: case color::type::indexed:
bg_color_node.add_attribute("indexed", std::to_string(fill_.get_background_color()->get_index())); bg_color_node.add_attribute("indexed", std::to_string(fill_.get_background_color()->get_index()));
break; break;
case color::type::rgb:
bg_color_node.add_attribute("rgb", fill_.get_background_color()->get_rgb_string());
break;
default: default:
throw std::runtime_error("bad type"); throw std::runtime_error("bad type");
} }
@ -846,6 +872,10 @@ xml_document style_serializer::write_stylesheet() const
{ {
color_node.add_attribute("theme", std::to_string(current_side->get_color()->get_theme())); color_node.add_attribute("theme", std::to_string(current_side->get_color()->get_theme()));
} }
else if (current_side->get_color()->get_type() == color::type::rgb)
{
color_node.add_attribute("rgb", current_side->get_color()->get_rgb_string());
}
else else
{ {
throw std::runtime_error("invalid color type"); throw std::runtime_error("invalid color type");

View File

@ -23,6 +23,7 @@
// @author: see AUTHORS file // @author: see AUTHORS file
#include <algorithm> #include <algorithm>
#include <xlnt/packaging/app_properties.hpp>
#include <xlnt/packaging/document_properties.hpp> #include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
#include <xlnt/packaging/relationship.hpp> #include <xlnt/packaging/relationship.hpp>
@ -110,6 +111,52 @@ void workbook_serializer::read_properties_core(const xml_document &xml)
} }
} }
void workbook_serializer::read_properties_app(const xml_document &xml)
{
auto &props = workbook_.get_app_properties();
auto root_node = xml.get_child("Properties");
if(root_node.has_child("Application"))
{
props.application = root_node.get_child("Application").get_text();
}
if(root_node.has_child("DocSecurity"))
{
props.doc_security = std::stoi(root_node.get_child("DocSecurity").get_text());
}
if(root_node.has_child("ScaleCrop"))
{
props.scale_crop = root_node.get_child("ScaleCrop").get_text() == "true";
}
if(root_node.has_child("Company"))
{
props.company = root_node.get_child("Company").get_text();
}
if(root_node.has_child("ScaleCrop"))
{
props.links_up_to_date = root_node.get_child("ScaleCrop").get_text() == "true";
}
if(root_node.has_child("SharedDoc"))
{
props.shared_doc = root_node.get_child("SharedDoc").get_text() == "true";
}
if(root_node.has_child("HyperlinksChanged"))
{
props.hyperlinks_changed = root_node.get_child("HyperlinksChanged").get_text() == "true";
}
if(root_node.has_child("AppVersion"))
{
props.app_version = root_node.get_child("AppVersion").get_text();
}
}
xml_document workbook_serializer::write_properties_core() const xml_document workbook_serializer::write_properties_core() const
{ {
auto &props = workbook_.get_properties(); auto &props = workbook_.get_properties();
@ -148,14 +195,25 @@ xml_document workbook_serializer::write_properties_app() const
xml.add_namespace("", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"); xml.add_namespace("", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
xml.add_namespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); xml.add_namespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
root_node.add_child("Application").set_text("Microsoft Excel"); auto &properties = workbook_.get_app_properties();
root_node.add_child("DocSecurity").set_text("0");
root_node.add_child("ScaleCrop").set_text("false"); root_node.add_child("Application").set_text(properties.application);
root_node.add_child("Company"); root_node.add_child("DocSecurity").set_text(std::to_string(properties.doc_security));
root_node.add_child("LinksUpToDate").set_text("false"); root_node.add_child("ScaleCrop").set_text(properties.scale_crop ? "true" : "false");
root_node.add_child("SharedDoc").set_text("false");
root_node.add_child("HyperlinksChanged").set_text("false"); auto company_node = root_node.add_child("Company");
root_node.add_child("AppVersion").set_text("12.0000");
if (!properties.company.empty())
{
company_node.set_text(properties.company);
}
root_node.add_child("LinksUpToDate").set_text(properties.links_up_to_date ? "true" : "false");
root_node.add_child("SharedDoc").set_text(properties.shared_doc ? "true" : "false");
root_node.add_child("HyperlinksChanged").set_text(properties.hyperlinks_changed ? "true" : "false");
root_node.add_child("AppVersion").set_text(properties.app_version);
// TODO what is this stuff?
auto heading_pairs_node = root_node.add_child("HeadingPairs"); auto heading_pairs_node = root_node.add_child("HeadingPairs");
auto heading_pairs_vector_node = heading_pairs_node.add_child("vt:vector"); auto heading_pairs_vector_node = heading_pairs_node.add_child("vt:vector");

View File

@ -28,6 +28,7 @@
#include <sstream> #include <sstream>
#include <xlnt/drawing/drawing.hpp> #include <xlnt/drawing/drawing.hpp>
#include <xlnt/packaging/app_properties.hpp>
#include <xlnt/packaging/document_properties.hpp> #include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
#include <xlnt/packaging/relationship.hpp> #include <xlnt/packaging/relationship.hpp>
@ -499,6 +500,17 @@ const document_properties &workbook::get_properties() const
return d_->properties_; return d_->properties_;
} }
app_properties &workbook::get_app_properties()
{
return d_->app_properties_;
}
const app_properties &workbook::get_app_properties() const
{
return d_->app_properties_;
}
void swap(workbook &left, workbook &right) void swap(workbook &left, workbook &right)
{ {
using std::swap; using std::swap;