mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
Merge pull request #294 from Crzyrndm/dev-worksheet-test-failures
Fix all round-tripping test failures and UTF encoding test failures
This commit is contained in:
commit
e1e4823908
72
include/xlnt/packaging/ext_list.hpp
Normal file
72
include/xlnt/packaging/ext_list.hpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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 <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/packaging/uri.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xml {
|
||||
class parser;
|
||||
class serializer;
|
||||
}
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
/// <summary>
|
||||
/// A list of xml extensions that may or may not be understood by the parser
|
||||
/// preservation is required for round-tripping even if extension is not understood
|
||||
/// [serialised: extLst]
|
||||
/// </summary>
|
||||
class XLNT_API ext_list
|
||||
{
|
||||
public:
|
||||
struct ext
|
||||
{
|
||||
public:
|
||||
ext(xml::parser &parser, const std::string& ns);
|
||||
ext(const uri& ID, const std::string& serialised);
|
||||
void serialise(xml::serializer &serialiser, const std::string& ns);
|
||||
|
||||
uri extension_ID_;
|
||||
std::string serialised_value_;
|
||||
};
|
||||
ext_list() = default; // default ctor required by xlnt::optional
|
||||
explicit ext_list(xml::parser &parser, const std::string& ns);
|
||||
void serialize(xml::serializer &serialiser, const std::string& ns);
|
||||
|
||||
void add_extension(const uri &ID, const std::string &element);
|
||||
|
||||
bool has_extension(const uri &extension_uri) const;
|
||||
|
||||
const ext &extension(const uri &extension_uri) const;
|
||||
|
||||
const std::vector<ext> &extensions() const;
|
||||
|
||||
private:
|
||||
std::vector<ext> extensions_;
|
||||
};
|
||||
} // namespace xlnt
|
|
@ -170,7 +170,7 @@ public:
|
|||
/// <summary>
|
||||
/// Returns the name of the font face.
|
||||
/// </summary>
|
||||
std::string name() const;
|
||||
const std::string& name() const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this font has a color applied.
|
||||
|
@ -232,7 +232,7 @@ public:
|
|||
/// <summary>
|
||||
/// Returns the scheme of this font.
|
||||
/// </summary>
|
||||
std::string scheme() const;
|
||||
const std::string& scheme() const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if left is exactly equal to right.
|
||||
|
@ -242,7 +242,10 @@ public:
|
|||
/// <summary>
|
||||
/// Returns true if left is not exactly equal to right.
|
||||
/// </summary>
|
||||
bool operator!=(const font &other) const;
|
||||
bool operator!=(const font &other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class style;
|
||||
|
|
44
include/xlnt/utils/serialisation_utils.hpp
Normal file
44
include/xlnt/utils/serialisation_utils.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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 <xlnt/xlnt_config.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace xlnt {
|
||||
/// <summary>
|
||||
/// Takes in any nuber and outputs a string form of that number which will
|
||||
/// serialise and deserialise without loss of precision
|
||||
/// </summary>
|
||||
template <typename Number>
|
||||
std::string serialize_number_to_string(Number num)
|
||||
{
|
||||
// more digits and excel won't match
|
||||
constexpr int Excel_Digit_Precision = 15; //sf
|
||||
std::stringstream ss;
|
||||
ss.precision(Excel_Digit_Precision);
|
||||
ss << num;
|
||||
return ss.str();
|
||||
}
|
||||
}
|
|
@ -51,6 +51,12 @@ public:
|
|||
/// </summary>
|
||||
optional<std::size_t> style;
|
||||
|
||||
/// <summary>
|
||||
/// Is this column sized to fit its content as best it can
|
||||
/// serialise if true
|
||||
/// </summary>
|
||||
bool best_fit = false;
|
||||
|
||||
/// <summary>
|
||||
/// If true, this column will be hidden
|
||||
/// </summary>
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/optional.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
|
@ -33,6 +34,7 @@ namespace xlnt {
|
|||
/// </summary>
|
||||
enum class XLNT_API orientation
|
||||
{
|
||||
default_orientation,
|
||||
portrait,
|
||||
landscape
|
||||
};
|
||||
|
@ -117,16 +119,6 @@ public:
|
|||
/// </summary>
|
||||
void paper_size(xlnt::paper_size paper_size);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the orientation of the worksheet using this page setup.
|
||||
/// </summary>
|
||||
xlnt::orientation orientation() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the orientation of the page.
|
||||
/// </summary>
|
||||
void orientation(xlnt::orientation orientation);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this worksheet should be scaled to fit on a single page during printing.
|
||||
/// </summary>
|
||||
|
@ -157,28 +149,6 @@ public:
|
|||
/// </summary>
|
||||
void fit_to_width(bool fit_to_width);
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the worksheet should be centered horizontall on the page if it takes
|
||||
/// up less than a full page.
|
||||
/// </summary>
|
||||
void horizontal_centered(bool horizontal_centered);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether horizontal centering has been enabled.
|
||||
/// </summary>
|
||||
bool horizontal_centered() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the worksheet should be vertically centered on the page if it takes
|
||||
/// up less than a full page.
|
||||
/// </summary>
|
||||
void vertical_centered(bool vertical_centered);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether vertical centering has been enabled.
|
||||
/// </summary>
|
||||
bool vertical_centered() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the factor by which the page should be scaled during printing.
|
||||
/// </summary>
|
||||
|
@ -189,6 +159,19 @@ public:
|
|||
/// </summary>
|
||||
double scale() const;
|
||||
|
||||
/// <summary>
|
||||
/// The orientation
|
||||
/// </summary>
|
||||
xlnt::optional<xlnt::orientation> orientation_;
|
||||
/// <summary>
|
||||
/// The horizontal dpi
|
||||
/// </summary>
|
||||
xlnt::optional<std::size_t> horizontal_dpi_;
|
||||
/// <summary>
|
||||
/// The vertical dpi
|
||||
/// </summary>
|
||||
xlnt::optional<std::size_t> vertical_dpi_;
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// The break
|
||||
|
@ -205,11 +188,6 @@ private:
|
|||
/// </summary>
|
||||
xlnt::paper_size paper_size_;
|
||||
|
||||
/// <summary>
|
||||
/// The orientation
|
||||
/// </summary>
|
||||
xlnt::orientation orientation_;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to fit to page
|
||||
/// </summary>
|
||||
|
@ -225,20 +203,10 @@ private:
|
|||
/// </summary>
|
||||
bool fit_to_width_;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to center the content horizontally
|
||||
/// </summary>
|
||||
bool horizontal_centered_;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to center the conent vertically
|
||||
/// </summary>
|
||||
bool vertical_centered_;
|
||||
|
||||
/// <summary>
|
||||
/// The amount to scale the worksheet
|
||||
/// </summary>
|
||||
double scale_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
} // namespace xlnt
|
165
include/xlnt/worksheet/phonetic_pr.hpp
Normal file
165
include/xlnt/worksheet/phonetic_pr.hpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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 <cstdint>
|
||||
#include <ostream>
|
||||
#include <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/optional.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
/// <summary>
|
||||
/// Phonetic properties
|
||||
/// Element provides a collection of properties that affect display of East Asian Languages
|
||||
/// [Serialised phoneticPr]
|
||||
/// </summary>
|
||||
class XLNT_API phonetic_pr
|
||||
{
|
||||
public:
|
||||
static const std::string Serialised_ID;
|
||||
|
||||
/// <summary>
|
||||
/// possible values for alignment property
|
||||
/// </summary>
|
||||
enum class align
|
||||
{
|
||||
center,
|
||||
distributed,
|
||||
left,
|
||||
no_control
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// possible values for type property
|
||||
/// </summary>
|
||||
enum class phonetic_type
|
||||
{
|
||||
full_width_katakana,
|
||||
half_width_katakana,
|
||||
hiragana,
|
||||
no_conversion
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// FontID represented by an unsigned 32-bit integer
|
||||
/// </summary>
|
||||
using font_id_t = std::uint32_t;
|
||||
|
||||
/// <summary>
|
||||
/// Default ctor for phonetic properties
|
||||
/// </summary>
|
||||
phonetic_pr() = default;
|
||||
|
||||
/// <summary>
|
||||
/// FontID ctor for phonetic properties
|
||||
/// </summary>
|
||||
explicit phonetic_pr(font_id_t font);
|
||||
|
||||
/// <summary>
|
||||
/// adds the xml serialised representation of this element to the stream
|
||||
/// </summary>
|
||||
void serialise(std::ostream& output_stream) const;
|
||||
|
||||
/// <summary>
|
||||
/// get the font index
|
||||
/// </summary>
|
||||
font_id_t font_id() const;
|
||||
|
||||
/// <summary>
|
||||
/// set the font index
|
||||
/// </summary>
|
||||
void font_id(font_id_t font);
|
||||
|
||||
/// <summary>
|
||||
/// is the phonetic type set
|
||||
/// </summary>
|
||||
bool has_type() const;
|
||||
|
||||
/// <summary>
|
||||
/// returns the phonetic type
|
||||
/// </summary>
|
||||
phonetic_type type() const;
|
||||
|
||||
/// <summary>
|
||||
/// sets the phonetic type
|
||||
/// </summary>
|
||||
void type(phonetic_type type);
|
||||
|
||||
/// <summary>
|
||||
/// is the alignment set
|
||||
/// </summary>
|
||||
bool has_alignment() const;
|
||||
|
||||
/// <summary>
|
||||
/// get the alignment
|
||||
/// </summary>
|
||||
align alignment() const;
|
||||
|
||||
/// <summary>
|
||||
/// set the alignment
|
||||
/// </summary>
|
||||
void alignment(align align);
|
||||
|
||||
// serialisation
|
||||
/// <summary>
|
||||
/// string form of the type enum
|
||||
/// </summary>
|
||||
static const std::string &type_as_string(phonetic_type type);
|
||||
|
||||
/// <summary>
|
||||
/// type enum from string
|
||||
/// </summary>
|
||||
static phonetic_type type_from_string(const std::string &str);
|
||||
|
||||
/// <summary>
|
||||
/// string form of alignment enum
|
||||
/// </summary>
|
||||
static const std::string &alignment_as_string(xlnt::phonetic_pr::align type);
|
||||
|
||||
/// <summary>
|
||||
/// alignment enum from string
|
||||
/// </summary>
|
||||
static align alignment_from_string(const std::string &str);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// zero based index into style sheet font record.
|
||||
/// Default: 0
|
||||
/// </summary>
|
||||
font_id_t font_id_ = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Type of characters to use.
|
||||
/// Default: full width katakana
|
||||
/// </summary>
|
||||
xlnt::optional<phonetic_type> type_;
|
||||
|
||||
/// <summary>
|
||||
/// align across the cell(s).
|
||||
/// Default: Left
|
||||
/// </summary>
|
||||
xlnt::optional<align> alignment_;
|
||||
};
|
||||
}
|
58
include/xlnt/worksheet/print_options.hpp
Normal file
58
include/xlnt/worksheet/print_options.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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 <xlnt/xlnt_config.hpp>
|
||||
#include <xlnt/utils/optional.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
struct XLNT_API print_options
|
||||
{
|
||||
/// <summary>
|
||||
/// if both grid_lines_set and this are true, grid lines are printed
|
||||
/// </summary>
|
||||
optional<bool> print_grid_lines;
|
||||
|
||||
/// <summary>
|
||||
/// if both print grid lines and this are true, grid lines are printed
|
||||
/// </summary>
|
||||
optional<bool> grid_lines_set;
|
||||
|
||||
/// <summary>
|
||||
/// print row and column headings
|
||||
/// </summary>
|
||||
optional<bool> print_headings;
|
||||
|
||||
/// <summary>
|
||||
/// center on page horizontally
|
||||
/// </summary>
|
||||
optional<bool> horizontal_centered;
|
||||
|
||||
/// <summary>
|
||||
/// center on page vertically
|
||||
/// </summary>
|
||||
optional<bool> vertical_centered;
|
||||
};
|
||||
} // namespace xlnt
|
|
@ -54,6 +54,11 @@ public:
|
|||
/// </summary>
|
||||
bool hidden = false;
|
||||
|
||||
/// <summary>
|
||||
/// True if row style should be applied
|
||||
/// </summary>
|
||||
optional<bool> custom_format;
|
||||
|
||||
/// <summary>
|
||||
/// The index to the style used by all cells in this row
|
||||
/// </summary>
|
||||
|
|
|
@ -36,6 +36,27 @@ namespace xlnt {
|
|||
class XLNT_API selection
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
/// default ctor
|
||||
/// </summary>
|
||||
explicit selection() = default;
|
||||
|
||||
/// <summary>
|
||||
/// ctor when no range selected
|
||||
/// sqref == active_cell
|
||||
/// </summary>
|
||||
explicit selection(pane_corner quadrant, cell_reference active_cell)
|
||||
: active_cell_(active_cell), sqref_(range_reference(active_cell, active_cell)), pane_(quadrant)
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// ctor with selected range
|
||||
/// sqref must contain active_cell
|
||||
/// </summary>
|
||||
explicit selection(pane_corner quadrant, cell_reference active_cell, range_reference selected)
|
||||
: active_cell_(active_cell), sqref_(selected), pane_(quadrant)
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this selection has a defined active cell.
|
||||
/// </summary>
|
||||
|
@ -121,17 +142,18 @@ public:
|
|||
|
||||
private:
|
||||
/// <summary>
|
||||
/// The active cell
|
||||
/// The last selected cell in the selection
|
||||
/// </summary>
|
||||
optional<cell_reference> active_cell_;
|
||||
|
||||
/// <summary>
|
||||
/// The range
|
||||
/// The last selected block in the selection
|
||||
/// contains active_cell_, normally == to active_cell_
|
||||
/// </summary>
|
||||
optional<range_reference> sqref_;
|
||||
|
||||
/// <summary>
|
||||
/// The quadrant
|
||||
/// The corner of the worksheet that this selection extends to
|
||||
/// </summary>
|
||||
pane_corner pane_;
|
||||
};
|
||||
|
|
|
@ -44,6 +44,11 @@ public:
|
|||
/// </summary>
|
||||
optional<double> default_row_height;
|
||||
|
||||
/// <summary>
|
||||
/// The default column width
|
||||
/// </summary>
|
||||
optional<double> default_column_width;
|
||||
|
||||
/// <summary>
|
||||
/// x14ac extension, dyDescent property
|
||||
/// </summary>
|
||||
|
|
81
include/xlnt/worksheet/sheet_pr.hpp
Normal file
81
include/xlnt/worksheet/sheet_pr.hpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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>
|
||||
#include <xlnt/utils/optional.hpp>
|
||||
#include <xlnt/cell/cell_reference.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
struct XLNT_API sheet_pr
|
||||
{
|
||||
/// <summary>
|
||||
/// is horizontally synced to the anchor point
|
||||
/// </summary>
|
||||
optional<bool> sync_horizontal;
|
||||
|
||||
/// <summary>
|
||||
/// is vertically synced to the anchor point
|
||||
/// </summary>
|
||||
optional<bool> sync_vertical;
|
||||
|
||||
/// <summary>
|
||||
/// Anchor point for worksheet's window
|
||||
/// </summary>
|
||||
optional<cell_reference> sync_ref;
|
||||
|
||||
/// <summary>
|
||||
/// Lotus compatibility option
|
||||
/// </summary>
|
||||
optional<bool> transition_evaluation;
|
||||
|
||||
/// <summary>
|
||||
/// Lotus compatibility option
|
||||
/// </summary>
|
||||
optional<bool> transition_entry;
|
||||
|
||||
/// <summary>
|
||||
/// worksheet is published
|
||||
/// </summary>
|
||||
optional<bool> published;
|
||||
|
||||
/// <summary>
|
||||
/// stable name of the sheet
|
||||
/// </summary>
|
||||
optional<std::string> code_name;
|
||||
|
||||
/// <summary>
|
||||
/// worksheet has one or more autofilters or advanced filters on
|
||||
/// </summary>
|
||||
optional<bool> filter_mode;
|
||||
|
||||
/// <summary>
|
||||
/// whether the conditional formatting calculations shall be evaluated
|
||||
/// </summary>
|
||||
optional<bool> enable_format_condition_calculation;
|
||||
};
|
||||
} // namespace xlnt
|
|
@ -192,6 +192,30 @@ public:
|
|||
return type_;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// has a top left cell?
|
||||
/// </summary>
|
||||
bool has_top_left_cell() const
|
||||
{
|
||||
return top_left_cell_.is_set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the top left cell of this view.
|
||||
/// </summary>
|
||||
void top_left_cell(const cell_reference& ref)
|
||||
{
|
||||
top_left_cell_.set(ref);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the top left cell of this view.
|
||||
/// </summary>
|
||||
cell_reference top_left_cell() const
|
||||
{
|
||||
return top_left_cell_.get();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this view is equal to rhs based on its id, grid lines setting,
|
||||
/// default grid color, pane, and selections.
|
||||
|
@ -202,7 +226,8 @@ public:
|
|||
&& show_grid_lines_ == rhs.show_grid_lines_
|
||||
&& default_grid_color_ == rhs.default_grid_color_
|
||||
&& pane_ == rhs.pane_
|
||||
&& selections_ == rhs.selections_;
|
||||
&& selections_ == rhs.selections_
|
||||
&& top_left_cell_ == rhs.top_left_cell_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -231,6 +256,11 @@ private:
|
|||
/// </summary>
|
||||
optional<xlnt::pane> pane_;
|
||||
|
||||
/// <summary>
|
||||
/// The top left cell
|
||||
/// </summary>
|
||||
optional<cell_reference> top_left_cell_;
|
||||
|
||||
/// <summary>
|
||||
/// The collection of selections
|
||||
/// </summary>
|
||||
|
|
|
@ -56,6 +56,7 @@ class relationship;
|
|||
class row_properties;
|
||||
class sheet_format_properties;
|
||||
class workbook;
|
||||
class phonetic_pr;
|
||||
|
||||
struct date;
|
||||
|
||||
|
@ -556,6 +557,21 @@ public:
|
|||
/// </summary>
|
||||
void reserve(std::size_t n);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this sheet has phonetic properties
|
||||
/// </summary>
|
||||
bool has_phonetic_properties() const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the phonetic properties of this sheet.
|
||||
/// </summary>
|
||||
const phonetic_pr &phonetic_properties() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the phonetic properties of this sheet to phonetic_props
|
||||
/// </summary>
|
||||
void phonetic_properties(const phonetic_pr& phonetic_props);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this sheet has a header/footer.
|
||||
/// </summary>
|
||||
|
|
|
@ -369,35 +369,25 @@ hyperlink cell::hyperlink() const
|
|||
|
||||
void cell::hyperlink(const std::string &url)
|
||||
{
|
||||
hyperlink(url, url);
|
||||
}
|
||||
|
||||
void cell::hyperlink(const std::string &url, const std::string &display)
|
||||
{
|
||||
if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end() || display.empty())
|
||||
if (url.empty() || std::find(url.begin(), url.end(), ':') == url.end())
|
||||
{
|
||||
throw invalid_parameter();
|
||||
}
|
||||
|
||||
auto ws = worksheet();
|
||||
auto &manifest = ws.workbook().manifest();
|
||||
bool existing = false;
|
||||
|
||||
d_->hyperlink_ = detail::hyperlink_impl();
|
||||
|
||||
// check for existing relationships
|
||||
for (const auto &rel : manifest.relationships(ws.path(), relationship_type::hyperlink))
|
||||
{
|
||||
if (rel.target().path().string() == url)
|
||||
{
|
||||
d_->hyperlink_.get().relationship = rel;
|
||||
existing = true;
|
||||
break;
|
||||
}
|
||||
auto relationships = manifest.relationships(ws.path(), relationship_type::hyperlink);
|
||||
auto relation = std::find_if(relationships.cbegin(), relationships.cend(),
|
||||
[&url](xlnt::relationship rel) { return rel.target().path().string() == url; });
|
||||
if (relation != relationships.end()) {
|
||||
d_->hyperlink_.get().relationship = *relation;
|
||||
}
|
||||
|
||||
// register a new relationship
|
||||
if (!existing) {
|
||||
else
|
||||
{ // register a new relationship
|
||||
auto rel_id = manifest.register_relationship(
|
||||
uri(ws.path().string()),
|
||||
relationship_type::hyperlink,
|
||||
|
@ -405,9 +395,25 @@ void cell::hyperlink(const std::string &url, const std::string &display)
|
|||
target_mode::external);
|
||||
// TODO: make manifest::register_relationship return the created relationship instead of rel id
|
||||
d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id);
|
||||
}
|
||||
|
||||
if (!has_value()) // hyperlink on an empty cell sets the value to the hyperlink string
|
||||
{
|
||||
value(url);
|
||||
}
|
||||
}
|
||||
|
||||
value(display);
|
||||
void cell::hyperlink(const std::string &url, const std::string &display)
|
||||
{
|
||||
if (!display.empty()) // if the display string isn't empty use that
|
||||
{
|
||||
value(display);
|
||||
}
|
||||
else // empty display string sets the value to the link text
|
||||
{
|
||||
value(url);
|
||||
}
|
||||
hyperlink(url);
|
||||
d_->hyperlink_.get().display = display;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,12 @@
|
|||
namespace xlnt {
|
||||
|
||||
rich_text::rich_text(const std::string &plain_text)
|
||||
: rich_text({plain_text, optional<font>()})
|
||||
: rich_text(rich_text_run{plain_text, optional<font>(), false})
|
||||
{
|
||||
}
|
||||
|
||||
rich_text::rich_text(const std::string &plain_text, const class font &text_font)
|
||||
: rich_text({plain_text, optional<font>(text_font)})
|
||||
: rich_text(rich_text_run{plain_text, optional<font>(text_font), false})
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
// @author: see AUTHORS file
|
||||
|
||||
#include <detail/header_footer/header_footer_code.hpp>
|
||||
#include <xlnt/utils/serialisation_utils.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
namespace detail {
|
||||
|
@ -359,6 +360,11 @@ std::array<xlnt::optional<xlnt::rich_text>, 3> decode_header_footer(const std::s
|
|||
|
||||
case hf_code::text_single_underline:
|
||||
{
|
||||
if (!current_run.second.is_set())
|
||||
{
|
||||
current_run.second = xlnt::font();
|
||||
}
|
||||
current_run.second.get().underline(font::underline_style::single);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -527,9 +533,25 @@ std::string encode_header_footer(const rich_text &t, header_footer::location whe
|
|||
if (run.second.get().has_size())
|
||||
{
|
||||
encoded.push_back('&');
|
||||
encoded.append(std::to_string(run.second.get().size()));
|
||||
encoded.append(serialize_number_to_string(run.second.get().size()));
|
||||
}
|
||||
if (run.second.get().underlined())
|
||||
{
|
||||
switch (run.second.get().underline())
|
||||
{
|
||||
case font::underline_style::single:
|
||||
case font::underline_style::single_accounting:
|
||||
encoded.append("&U");
|
||||
break;
|
||||
case font::underline_style::double_:
|
||||
case font::underline_style::double_accounting:
|
||||
encoded.append("&E");
|
||||
break;
|
||||
default:
|
||||
case font::underline_style::none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (run.second.get().has_color())
|
||||
{
|
||||
encoded.push_back('&');
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <detail/implementations/stylesheet.hpp>
|
||||
#include <detail/implementations/worksheet_impl.hpp>
|
||||
#include <xlnt/packaging/ext_list.hpp>
|
||||
#include <xlnt/packaging/manifest.hpp>
|
||||
#include <xlnt/utils/datetime.hpp>
|
||||
#include <xlnt/utils/variant.hpp>
|
||||
|
@ -123,6 +124,7 @@ struct workbook_impl
|
|||
optional<calculation_properties> calculation_properties_;
|
||||
optional<std::string> abs_path_;
|
||||
optional<std::size_t> arch_id_flags_;
|
||||
optional<ext_list> extensions_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -27,15 +27,19 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
#include <xlnt/packaging/ext_list.hpp>
|
||||
#include <xlnt/workbook/named_range.hpp>
|
||||
#include <xlnt/worksheet/column_properties.hpp>
|
||||
#include <xlnt/worksheet/header_footer.hpp>
|
||||
#include <xlnt/worksheet/phonetic_pr.hpp>
|
||||
#include <xlnt/worksheet/range.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
#include <xlnt/worksheet/row_properties.hpp>
|
||||
#include <xlnt/worksheet/sheet_format_properties.hpp>
|
||||
#include <xlnt/worksheet/sheet_view.hpp>
|
||||
#include <xlnt/worksheet/print_options.hpp>
|
||||
#include <xlnt/worksheet/sheet_pr.hpp>
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
|
@ -72,6 +76,7 @@ struct worksheet_impl
|
|||
page_margins_ = other.page_margins_;
|
||||
merged_cells_ = other.merged_cells_;
|
||||
named_ranges_ = other.named_ranges_;
|
||||
phonetic_properties_ = other.phonetic_properties_;
|
||||
header_footer_ = other.header_footer_;
|
||||
print_title_cols_ = other.print_title_cols_;
|
||||
print_title_rows_ = other.print_title_rows_;
|
||||
|
@ -79,6 +84,9 @@ struct worksheet_impl
|
|||
views_ = other.views_;
|
||||
column_breaks_ = other.column_breaks_;
|
||||
row_breaks_ = other.row_breaks_;
|
||||
extension_list_ = other.extension_list_;
|
||||
sheet_properties_ = other.sheet_properties_;
|
||||
print_options_ = other.print_options_;
|
||||
|
||||
for (auto &row : cell_map_)
|
||||
{
|
||||
|
@ -107,6 +115,7 @@ struct worksheet_impl
|
|||
std::vector<range_reference> merged_cells_;
|
||||
std::unordered_map<std::string, named_range> named_ranges_;
|
||||
|
||||
optional<phonetic_pr> phonetic_properties_;
|
||||
optional<header_footer> header_footer_;
|
||||
|
||||
std::string print_title_cols_;
|
||||
|
@ -120,6 +129,10 @@ struct worksheet_impl
|
|||
std::vector<row_t> row_breaks_;
|
||||
|
||||
std::unordered_map<std::string, comment> comments_;
|
||||
optional<print_options> print_options_;
|
||||
optional<sheet_pr> sheet_properties_;
|
||||
|
||||
optional<ext_list> extension_list_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
|
|
@ -343,5 +343,19 @@ std::string to_string(pane_state state)
|
|||
default_case("frozen");
|
||||
}
|
||||
|
||||
std::string to_string(orientation orientation)
|
||||
{
|
||||
switch (orientation)
|
||||
{
|
||||
case orientation::default_orientation:
|
||||
return "default";
|
||||
case orientation::landscape:
|
||||
return "landscape";
|
||||
case orientation::portrait:
|
||||
return "portrait";
|
||||
}
|
||||
default_case("default");
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <xlnt/utils/exceptions.hpp>
|
||||
#include <xlnt/utils/variant.hpp>
|
||||
#include <xlnt/worksheet/pane.hpp>
|
||||
#include <xlnt/worksheet/page_setup.hpp>
|
||||
#include <xlnt/workbook/metadata_property.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
@ -76,6 +77,8 @@ std::string to_string(target_mode mode);
|
|||
|
||||
std::string to_string(pane_state state);
|
||||
|
||||
std::string to_string(orientation state);
|
||||
|
||||
template<typename T>
|
||||
static T from_string(const std::string &string_value);
|
||||
|
||||
|
@ -198,7 +201,11 @@ pattern_fill_type from_string(const std::string &string)
|
|||
auto toLower = [](std::string str) {
|
||||
auto bg{ std::begin (str) };
|
||||
auto en{ std::end (str) };
|
||||
std::transform (bg, en, bg, tolower);
|
||||
std::transform(bg, en, bg,
|
||||
[](char c) {
|
||||
// static cast to avoid int -> char narrowing warning
|
||||
return static_cast<char>(tolower(c));
|
||||
});
|
||||
|
||||
return str;
|
||||
};
|
||||
|
@ -390,6 +397,15 @@ pane_corner from_string(const std::string &string)
|
|||
default_case(pane_corner::bottom_left);
|
||||
}
|
||||
|
||||
template <>
|
||||
orientation from_string(const std::string &string)
|
||||
{
|
||||
if (string == "default") return orientation::default_orientation;
|
||||
else if (string == "landscape") return orientation::landscape;
|
||||
else if (string == "portrait") return orientation::portrait;
|
||||
default_case(orientation::default);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace xlnt
|
||||
|
||||
|
@ -578,6 +594,20 @@ struct value_traits<xlnt::extended_property>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct value_traits<xlnt::orientation>
|
||||
{
|
||||
static xlnt::orientation parse(std::string string, const parser &)
|
||||
{
|
||||
return xlnt::detail::from_string<xlnt::orientation>(string);
|
||||
}
|
||||
|
||||
static std::string serialize(xlnt::orientation orientation, const serializer &)
|
||||
{
|
||||
return xlnt::detail::to_string(orientation);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xml
|
||||
|
||||
|
||||
|
|
|
@ -26,13 +26,6 @@
|
|||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <detail/constants.hpp>
|
||||
#include <detail/header_footer/header_footer_code.hpp>
|
||||
#include <detail/implementations/workbook_impl.hpp>
|
||||
#include <detail/serialization/custom_value_traits.hpp>
|
||||
#include <detail/serialization/vector_streambuf.hpp>
|
||||
#include <detail/serialization/xlsx_consumer.hpp>
|
||||
#include <detail/serialization/zstream.hpp>
|
||||
#include <xlnt/cell/cell.hpp>
|
||||
#include <xlnt/cell/comment.hpp>
|
||||
#include <xlnt/cell/hyperlink.hpp>
|
||||
|
@ -42,6 +35,13 @@
|
|||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/selection.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <detail/constants.hpp>
|
||||
#include <detail/header_footer/header_footer_code.hpp>
|
||||
#include <detail/implementations/workbook_impl.hpp>
|
||||
#include <detail/serialization/custom_value_traits.hpp>
|
||||
#include <detail/serialization/vector_streambuf.hpp>
|
||||
#include <detail/serialization/xlsx_consumer.hpp>
|
||||
#include <detail/serialization/zstream.hpp>
|
||||
|
||||
namespace std {
|
||||
|
||||
|
@ -221,9 +221,9 @@ cell xlsx_consumer::read_cell()
|
|||
row_properties.dy_descent = parser().attribute<double>(qn("x14ac", "dyDescent"));
|
||||
}
|
||||
|
||||
skip_attributes({ "customFormat", "s", "customFont",
|
||||
skip_attributes({"customFormat", "s", "customFont",
|
||||
"outlineLevel", "collapsed", "thickTop", "thickBot",
|
||||
"ph", "spans" });
|
||||
"ph", "spans"});
|
||||
}
|
||||
|
||||
if (!in_element(qn("spreadsheetml", "row")))
|
||||
|
@ -246,7 +246,7 @@ cell xlsx_consumer::read_cell()
|
|||
|
||||
if (parser().attribute_present("s"))
|
||||
{
|
||||
cell.format(target_.format(std::stoull(parser().attribute("s"))));
|
||||
cell.format(target_.format(static_cast<std::size_t>(std::stoull(parser().attribute("s")))));
|
||||
}
|
||||
|
||||
auto has_value = false;
|
||||
|
@ -274,8 +274,8 @@ cell xlsx_consumer::read_cell()
|
|||
has_shared_formula = parser().attribute("t") == "shared";
|
||||
}
|
||||
|
||||
skip_attributes({ "aca", "ref", "dt2D", "dtr", "del1",
|
||||
"del2", "r1", "r2", "ca", "si", "bx" });
|
||||
skip_attributes({"aca", "ref", "dt2D", "dtr", "del1",
|
||||
"del2", "r1", "r2", "ca", "si", "bx"});
|
||||
|
||||
formula_value_string = read_text();
|
||||
}
|
||||
|
@ -367,13 +367,13 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
|
||||
target_.d_->sheet_title_rel_id_map_.end(),
|
||||
[&](const std::pair<std::string, std::string> &p) {
|
||||
return p.second == rel_id;
|
||||
})->first;
|
||||
return p.second == rel_id;
|
||||
})->first;
|
||||
|
||||
auto ws = worksheet(current_worksheet_);
|
||||
|
||||
expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet
|
||||
skip_attributes({ qn("mc", "Ignorable") });
|
||||
skip_attributes({qn("mc", "Ignorable")});
|
||||
|
||||
while (in_element(qn("spreadsheetml", "worksheet")))
|
||||
{
|
||||
|
@ -381,6 +381,44 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
|
||||
if (current_worksheet_element == qn("spreadsheetml", "sheetPr")) // CT_SheetPr 0-1
|
||||
{
|
||||
sheet_pr props;
|
||||
if (parser().attribute_present("syncHorizontal"))
|
||||
{ // optional, boolean, false
|
||||
props.sync_horizontal.set(parser().attribute<bool>("syncHorizontal"));
|
||||
}
|
||||
if (parser().attribute_present("syncVertical"))
|
||||
{// optional, boolean, false
|
||||
props.sync_vertical.set(parser().attribute<bool>("syncVertical"));
|
||||
}
|
||||
if (parser().attribute_present("syncRef"))
|
||||
{ // optional, ST_Ref, false
|
||||
props.sync_ref.set(cell_reference(parser().attribute("syncRef")));
|
||||
}
|
||||
if (parser().attribute_present("transitionEvaluation"))
|
||||
{ // optional, boolean, false
|
||||
props.transition_evaluation.set(parser().attribute<bool>("transitionEvaluation"));
|
||||
}
|
||||
if (parser().attribute_present("transitionEntry"))
|
||||
{// optional, boolean, false
|
||||
props.transition_entry.set(parser().attribute<bool>("transitionEntry"));
|
||||
}
|
||||
if (parser().attribute_present("published"))
|
||||
{// optional, boolean, true
|
||||
props.published.set(parser().attribute<bool>("published"));
|
||||
}
|
||||
if (parser().attribute_present("codeName"))
|
||||
{ // optional, string
|
||||
props.code_name.set(parser().attribute<std::string>("codeName"));
|
||||
}
|
||||
if (parser().attribute_present("filterMode"))
|
||||
{// optional, boolean, false
|
||||
props.filter_mode.set(parser().attribute<bool>("filterMode"));
|
||||
}
|
||||
if (parser().attribute_present("enableFormatConditionsCalculation"))
|
||||
{// optional, boolean, true
|
||||
props.enable_format_condition_calculation.set(parser().attribute<bool>("enableFormatConditionsCalculation"));
|
||||
}
|
||||
ws.d_->sheet_properties_.set(props);
|
||||
while (in_element(current_worksheet_element))
|
||||
{
|
||||
auto sheet_pr_child_element = expect_start_element(xml::content::simple);
|
||||
|
@ -408,16 +446,6 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
|
||||
expect_end_element(sheet_pr_child_element);
|
||||
}
|
||||
|
||||
skip_attribute("syncHorizontal"); // optional, boolean, false
|
||||
skip_attribute("syncVertical"); // optional, boolean, false
|
||||
skip_attribute("syncRef"); // optional, ST_Ref, false
|
||||
skip_attribute("transitionEvaluation"); // optional, boolean, false
|
||||
skip_attribute("transitionEntry"); // optional, boolean, false
|
||||
skip_attribute("published"); // optional, boolean, true
|
||||
skip_attribute("codeName"); // optional, string
|
||||
skip_attribute("filterMode"); // optional, boolean, false
|
||||
skip_attribute("enableFormatConditionsCalculation"); // optional, boolean, true
|
||||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "dimension")) // CT_SheetDimension 0-1
|
||||
{
|
||||
|
@ -436,6 +464,10 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
{
|
||||
new_view.show_grid_lines(is_true(parser().attribute("showGridLines")));
|
||||
}
|
||||
if (parser().attribute_present("topLeftCell"))
|
||||
{
|
||||
new_view.top_left_cell(cell_reference(parser().attribute("topLeftCell")));
|
||||
}
|
||||
|
||||
if (parser().attribute_present("defaultGridColor")) // default="true"
|
||||
{
|
||||
|
@ -446,8 +478,8 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
&& parser().attribute("view") != "normal")
|
||||
{
|
||||
new_view.type(parser().attribute("view") == "pageBreakPreview"
|
||||
? sheet_view_type::page_break_preview
|
||||
: sheet_view_type::page_layout);
|
||||
? sheet_view_type::page_break_preview
|
||||
: sheet_view_type::page_layout);
|
||||
}
|
||||
|
||||
if (parser().attribute_present("tabSelected")
|
||||
|
@ -456,9 +488,9 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
target_.d_->view_.get().active_tab = ws.id() - 1;
|
||||
}
|
||||
|
||||
skip_attributes({ "windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft", "showRuler", "showOutlineSymbols", "showWhiteSpace",
|
||||
skip_attributes({"windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft", "showRuler", "showOutlineSymbols", "showWhiteSpace",
|
||||
"view", "topLeftCell", "colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView",
|
||||
"zoomScalePageLayoutView" });
|
||||
"zoomScalePageLayoutView"});
|
||||
|
||||
while (in_element(qn("spreadsheetml", "sheetView")))
|
||||
{
|
||||
|
@ -509,7 +541,7 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
const auto sqref = range_reference(parser().attribute("sqref"));
|
||||
current_selection.sqref(sqref);
|
||||
}
|
||||
|
||||
|
||||
current_selection.pane(pane_corner::top_left);
|
||||
|
||||
new_view.add_selection(current_selection);
|
||||
|
@ -544,7 +576,11 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
ws.d_->format_properties_.base_col_width =
|
||||
parser().attribute<double>("baseColWidth");
|
||||
}
|
||||
|
||||
if (parser().attribute_present("defaultColWidth"))
|
||||
{
|
||||
ws.d_->format_properties_.default_column_width =
|
||||
parser().attribute<double>("defaultColWidth");
|
||||
}
|
||||
if (parser().attribute_present("defaultRowHeight"))
|
||||
{
|
||||
ws.d_->format_properties_.default_row_height =
|
||||
|
@ -565,7 +601,7 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
{
|
||||
expect_start_element(qn("spreadsheetml", "col"), xml::content::simple);
|
||||
|
||||
skip_attributes({ "bestFit", "collapsed", "outlineLevel" });
|
||||
skip_attributes({"bestFit", "collapsed", "outlineLevel"});
|
||||
|
||||
auto min = static_cast<column_t::index_t>(std::stoull(parser().attribute("min")));
|
||||
auto max = static_cast<column_t::index_t>(std::stoull(parser().attribute("max")));
|
||||
|
@ -585,9 +621,14 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
}
|
||||
|
||||
auto custom = parser().attribute_present("customWidth")
|
||||
? is_true(parser().attribute("customWidth")) : false;
|
||||
? is_true(parser().attribute("customWidth"))
|
||||
: false;
|
||||
auto hidden = parser().attribute_present("hidden")
|
||||
? is_true(parser().attribute("hidden")) : false;
|
||||
? is_true(parser().attribute("hidden"))
|
||||
: false;
|
||||
auto best_fit = parser().attribute_present("bestFit")
|
||||
? is_true(parser().attribute("bestFit"))
|
||||
: false;
|
||||
|
||||
expect_end_element(qn("spreadsheetml", "col"));
|
||||
|
||||
|
@ -607,6 +648,7 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
|
|||
|
||||
props.hidden = hidden;
|
||||
props.custom_width = custom;
|
||||
props.best_fit = best_fit;
|
||||
ws.add_column_properties(column, props);
|
||||
}
|
||||
}
|
||||
|
@ -659,9 +701,18 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
row_properties.dy_descent = parser().attribute<double>(qn("x14ac", "dyDescent"));
|
||||
}
|
||||
|
||||
skip_attributes({ "customFormat", "s", "customFont",
|
||||
if (parser().attribute_present("s"))
|
||||
{
|
||||
row_properties.style.set(static_cast<std::size_t>(std::stoull(parser().attribute("s"))));
|
||||
}
|
||||
if (parser().attribute_present("customFormat"))
|
||||
{
|
||||
row_properties.custom_format.set(parser().attribute<bool>("customFormat"));
|
||||
}
|
||||
|
||||
skip_attributes({"customFont",
|
||||
"outlineLevel", "collapsed", "thickTop", "thickBot",
|
||||
"ph", "spans" });
|
||||
"ph", "spans"});
|
||||
|
||||
while (in_element(qn("spreadsheetml", "row")))
|
||||
{
|
||||
|
@ -673,7 +724,7 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
|
||||
if (parser().attribute_present("s"))
|
||||
{
|
||||
cell.format(target_.format(std::stoull(parser().attribute("s"))));
|
||||
cell.format(target_.format(static_cast<std::size_t>(std::stoull(parser().attribute("s")))));
|
||||
}
|
||||
|
||||
auto has_value = false;
|
||||
|
@ -702,7 +753,7 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
}
|
||||
|
||||
skip_attributes(
|
||||
{ "aca", "ref", "dt2D", "dtr", "del1", "del2", "r1", "r2", "ca", "si", "bx" });
|
||||
{"aca", "ref", "dt2D", "dtr", "del1", "del2", "r1", "r2", "ca", "si", "bx"});
|
||||
|
||||
formula_value_string = read_text();
|
||||
}
|
||||
|
@ -757,7 +808,6 @@ void xlsx_consumer::read_worksheet_sheetdata()
|
|||
cell.error(value_string);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
expect_end_element(qn("spreadsheetml", "row"));
|
||||
|
@ -835,7 +885,16 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "phoneticPr")) // CT_PhoneticPr 0-1
|
||||
{
|
||||
skip_remaining_content(current_worksheet_element);
|
||||
phonetic_pr phonetic_properties(parser().attribute<std::uint32_t>("fontId"));
|
||||
if (parser().attribute_present("type"))
|
||||
{
|
||||
phonetic_properties.type(phonetic_pr::type_from_string(parser().attribute("type")));
|
||||
}
|
||||
if (parser().attribute_present("alignment"))
|
||||
{
|
||||
phonetic_properties.alignment(phonetic_pr::alignment_from_string(parser().attribute("alignment")));
|
||||
}
|
||||
current_worksheet_->phonetic_properties_.set(phonetic_properties);
|
||||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "conditionalFormatting")) // CT_ConditionalFormatting 0+
|
||||
{
|
||||
|
@ -847,7 +906,7 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "hyperlinks")) // CT_Hyperlinks 0-1
|
||||
{
|
||||
while (in_element(qn("spreadsheetml", "hyperlinks")))
|
||||
while (in_element(current_worksheet_element))
|
||||
{
|
||||
// CT_Hyperlink
|
||||
expect_start_element(qn("spreadsheetml", "hyperlink"), xml::content::simple);
|
||||
|
@ -900,6 +959,28 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "printOptions")) // CT_PrintOptions 0-1
|
||||
{
|
||||
print_options opts;
|
||||
if (parser().attribute_present("gridLines"))
|
||||
{
|
||||
opts.print_grid_lines.set(parser().attribute<bool>("gridLines"));
|
||||
}
|
||||
if (parser().attribute_present("gridLinesSet"))
|
||||
{
|
||||
opts.print_grid_lines.set(parser().attribute<bool>("gridLinesSet"));
|
||||
}
|
||||
if (parser().attribute_present("headings"))
|
||||
{
|
||||
opts.print_grid_lines.set(parser().attribute<bool>("headings"));
|
||||
}
|
||||
if (parser().attribute_present("horizontalCentered"))
|
||||
{
|
||||
opts.print_grid_lines.set(parser().attribute<bool>("horizontalCentered"));
|
||||
}
|
||||
if (parser().attribute_present("verticalCentered"))
|
||||
{
|
||||
opts.print_grid_lines.set(parser().attribute<bool>("verticalCentered"));
|
||||
}
|
||||
ws.d_->print_options_.set(opts);
|
||||
skip_remaining_content(current_worksheet_element);
|
||||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "pageMargins")) // CT_PageMargins 0-1
|
||||
|
@ -917,6 +998,20 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "pageSetup")) // CT_PageSetup 0-1
|
||||
{
|
||||
page_setup setup;
|
||||
if (parser().attribute_present("orientation"))
|
||||
{
|
||||
setup.orientation_.set(parser().attribute<orientation>("orientation"));
|
||||
}
|
||||
if (parser().attribute_present("horizontalDpi"))
|
||||
{
|
||||
setup.horizontal_dpi_.set(parser().attribute<std::size_t>("horizontalDpi"));
|
||||
}
|
||||
if (parser().attribute_present("verticalDpi"))
|
||||
{
|
||||
setup.vertical_dpi_.set(parser().attribute<std::size_t>("verticalDpi"));
|
||||
}
|
||||
ws.page_setup(setup);
|
||||
skip_remaining_content(current_worksheet_element);
|
||||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "headerFooter")) // CT_HeaderFooter 0-1
|
||||
|
@ -980,7 +1075,7 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
for (std::size_t i = 0; i < 3; ++i)
|
||||
{
|
||||
auto loc = i == 0 ? header_footer::location::left
|
||||
: i == 1 ? header_footer::location::center : header_footer::location::right;
|
||||
: i == 1 ? header_footer::location::center : header_footer::location::right;
|
||||
|
||||
if (different_odd_even)
|
||||
{
|
||||
|
@ -1020,7 +1115,8 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
{
|
||||
auto count = parser().attribute_present("count") ? parser().attribute<std::size_t>("count") : 0;
|
||||
auto manual_break_count = parser().attribute_present("manualBreakCount")
|
||||
? parser().attribute<std::size_t>("manualBreakCount") : 0;
|
||||
? parser().attribute<std::size_t>("manualBreakCount")
|
||||
: 0;
|
||||
|
||||
while (in_element(qn("spreadsheetml", "rowBreaks")))
|
||||
{
|
||||
|
@ -1037,7 +1133,7 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
--manual_break_count;
|
||||
}
|
||||
|
||||
skip_attributes({ "min", "max", "pt" });
|
||||
skip_attributes({"min", "max", "pt"});
|
||||
expect_end_element(qn("spreadsheetml", "brk"));
|
||||
}
|
||||
}
|
||||
|
@ -1063,7 +1159,7 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
--manual_break_count;
|
||||
}
|
||||
|
||||
skip_attributes({ "min", "max", "pt" });
|
||||
skip_attributes({"min", "max", "pt"});
|
||||
expect_end_element(qn("spreadsheetml", "brk"));
|
||||
}
|
||||
}
|
||||
|
@ -1093,7 +1189,8 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
}
|
||||
else if (current_worksheet_element == qn("spreadsheetml", "extLst"))
|
||||
{
|
||||
skip_remaining_content(current_worksheet_element);
|
||||
ext_list extensions(parser(), current_worksheet_element.namespace_());
|
||||
ws.d_->extension_list_.set(extensions);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1107,8 +1204,8 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
|
||||
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::comments))
|
||||
{
|
||||
auto comments_part = manifest.canonicalize({ workbook_rel, sheet_rel,
|
||||
manifest.relationship(sheet_path, xlnt::relationship_type::comments) });
|
||||
auto comments_part = manifest.canonicalize({workbook_rel, sheet_rel,
|
||||
manifest.relationship(sheet_path, xlnt::relationship_type::comments)});
|
||||
|
||||
auto receive = xml::parser::receive_default;
|
||||
auto comments_part_streambuf = archive_->open(comments_part);
|
||||
|
@ -1120,8 +1217,8 @@ worksheet xlsx_consumer::read_worksheet_end(const std::string &rel_id)
|
|||
|
||||
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::vml_drawing))
|
||||
{
|
||||
auto vml_drawings_part = manifest.canonicalize({ workbook_rel, sheet_rel,
|
||||
manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing) });
|
||||
auto vml_drawings_part = manifest.canonicalize({workbook_rel, sheet_rel,
|
||||
manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing)});
|
||||
|
||||
auto vml_drawings_part_streambuf = archive_->open(comments_part);
|
||||
std::istream vml_drawings_part_stream(comments_part_streambuf.get());
|
||||
|
@ -1148,8 +1245,7 @@ bool xlsx_consumer::has_cell()
|
|||
|
||||
std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
|
||||
{
|
||||
const auto part_rels_path = part.parent().append("_rels")
|
||||
.append(part.filename() + ".rels").relative_to(path("/"));
|
||||
const auto part_rels_path = part.parent().append("_rels").append(part.filename() + ".rels").relative_to(path("/"));
|
||||
|
||||
std::vector<xlnt::relationship> relationships;
|
||||
if (!archive_->has_file(part_rels_path)) return relationships;
|
||||
|
@ -1357,8 +1453,8 @@ void xlsx_consumer::populate_workbook(bool streaming)
|
|||
}
|
||||
}
|
||||
|
||||
read_part({ manifest().relationship(root_path,
|
||||
relationship_type::office_document) });
|
||||
read_part({manifest().relationship(root_path,
|
||||
relationship_type::office_document)});
|
||||
}
|
||||
|
||||
// Package Parts
|
||||
|
@ -1455,14 +1551,16 @@ void xlsx_consumer::read_custom_properties()
|
|||
|
||||
void xlsx_consumer::read_office_document(const std::string &content_type) // CT_Workbook
|
||||
{
|
||||
if (content_type != "application/vnd."
|
||||
"openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
|
||||
&& content_type != "application/vnd."
|
||||
"openxmlformats-officedocument.spreadsheetml.template.main+xml")
|
||||
if (content_type !=
|
||||
"application/vnd."
|
||||
"openxmlformats-officedocument.spreadsheetml.sheet.main+xml"
|
||||
&& content_type !=
|
||||
"application/vnd."
|
||||
"openxmlformats-officedocument.spreadsheetml.template.main+xml")
|
||||
{
|
||||
throw xlnt::invalid_file(content_type);
|
||||
}
|
||||
|
||||
|
||||
target_.d_->calculation_properties_.clear();
|
||||
|
||||
expect_start_element(qn("workbook", "workbook"), xml::content::complex);
|
||||
|
@ -1532,8 +1630,9 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
|
|||
else if (current_workbook_element == qn("workbook", "workbookPr")) // CT_WorkbookPr 0-1
|
||||
{
|
||||
target_.base_date(parser().attribute_present("date1904") // optional, bool=false
|
||||
&& is_true(parser().attribute("date1904"))
|
||||
? calendar::mac_1904 : calendar::windows_1900);
|
||||
&& is_true(parser().attribute("date1904"))
|
||||
? calendar::mac_1904
|
||||
: calendar::windows_1900);
|
||||
skip_attribute("showObjects"); // optional, ST_Objects="all"
|
||||
skip_attribute("showBorderUnselectedTables"); // optional, bool=true
|
||||
skip_attribute("filterPrivacy"); // optional, bool=false
|
||||
|
@ -1759,7 +1858,7 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
|
|||
|
||||
if (!streaming_)
|
||||
{
|
||||
read_part({ workbook_rel, worksheet_rel });
|
||||
read_part({workbook_rel, worksheet_rel});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2224,36 +2323,40 @@ void xlsx_consumer::read_stylesheet()
|
|||
expect_start_element(qn("spreadsheetml", "xf"), xml::content::complex);
|
||||
|
||||
auto &record = *(!in_style_records
|
||||
? format_records.emplace(format_records.end())
|
||||
: style_records.emplace(style_records.end()));
|
||||
? format_records.emplace(format_records.end())
|
||||
: style_records.emplace(style_records.end()));
|
||||
|
||||
if (parser().attribute_present("applyBorder"))
|
||||
{
|
||||
record.first.border_applied = is_true(parser().attribute("applyBorder"));
|
||||
}
|
||||
record.first.border_id = parser().attribute_present("borderId")
|
||||
? parser().attribute<std::size_t>("borderId") : 0;
|
||||
? parser().attribute<std::size_t>("borderId")
|
||||
: 0;
|
||||
|
||||
if (parser().attribute_present("applyFill"))
|
||||
{
|
||||
record.first.fill_applied = is_true(parser().attribute("applyFill"));
|
||||
}
|
||||
record.first.fill_id = parser().attribute_present("fillId")
|
||||
? parser().attribute<std::size_t>("fillId") : 0;
|
||||
? parser().attribute<std::size_t>("fillId")
|
||||
: 0;
|
||||
|
||||
if (parser().attribute_present("applyFont"))
|
||||
{
|
||||
record.first.font_applied = is_true(parser().attribute("applyFont"));
|
||||
}
|
||||
record.first.font_id = parser().attribute_present("fontId")
|
||||
? parser().attribute<std::size_t>("fontId") : 0;
|
||||
? parser().attribute<std::size_t>("fontId")
|
||||
: 0;
|
||||
|
||||
if (parser().attribute_present("applyNumberFormat"))
|
||||
{
|
||||
record.first.number_format_applied = is_true(parser().attribute("applyNumberFormat"));
|
||||
}
|
||||
record.first.number_format_id = parser().attribute_present("numFmtId")
|
||||
? parser().attribute<std::size_t>("numFmtId") : 0;
|
||||
? parser().attribute<std::size_t>("numFmtId")
|
||||
: 0;
|
||||
|
||||
auto apply_alignment_present = parser().attribute_present("applyAlignment");
|
||||
if (apply_alignment_present)
|
||||
|
@ -2544,7 +2647,7 @@ void xlsx_consumer::read_comments(worksheet ws)
|
|||
|
||||
expect_start_element(qn("spreadsheetml", "comments"), xml::content::complex);
|
||||
// name space can be ignored
|
||||
skip_attribute(qn("mc","Ignorable"));
|
||||
skip_attribute(qn("mc", "Ignorable"));
|
||||
expect_start_element(qn("spreadsheetml", "authors"), xml::content::complex);
|
||||
|
||||
while (in_element(qn("spreadsheetml", "authors")))
|
||||
|
@ -2571,12 +2674,12 @@ void xlsx_consumer::read_comments(worksheet ws)
|
|||
|
||||
expect_end_element(qn("spreadsheetml", "text"));
|
||||
|
||||
if (in_element(xml::qname(qn("spreadsheetml", "comment"))))
|
||||
{
|
||||
expect_start_element(qn("mc", "AlternateContent"), xml::content::complex);
|
||||
skip_remaining_content(qn("mc", "AlternateContent"));
|
||||
expect_end_element(qn("mc", "AlternateContent"));
|
||||
}
|
||||
if (in_element(xml::qname(qn("spreadsheetml", "comment"))))
|
||||
{
|
||||
expect_start_element(qn("mc", "AlternateContent"), xml::content::complex);
|
||||
skip_remaining_content(qn("mc", "AlternateContent"));
|
||||
expect_end_element(qn("mc", "AlternateContent"));
|
||||
}
|
||||
|
||||
expect_end_element(qn("spreadsheetml", "comment"));
|
||||
}
|
||||
|
@ -2779,7 +2882,8 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
|||
auto text_element = expect_start_element(xml::content::mixed);
|
||||
const auto xml_space = qn("xml", "space");
|
||||
const auto preserve_space = parser().attribute_present(xml_space)
|
||||
? parser().attribute(xml_space) == "preserve" : false;
|
||||
? parser().attribute(xml_space) == "preserve"
|
||||
: false;
|
||||
skip_attributes();
|
||||
auto text = read_text();
|
||||
|
||||
|
@ -2831,12 +2935,14 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
|
|||
else if (current_run_property_element == xml::qname(xmlns, "b"))
|
||||
{
|
||||
run.second.get().bold(parser().attribute_present("val")
|
||||
? is_true(parser().attribute("val")) : true);
|
||||
? is_true(parser().attribute("val"))
|
||||
: true);
|
||||
}
|
||||
else if (current_run_property_element == xml::qname(xmlns, "i"))
|
||||
{
|
||||
run.second.get().italic(parser().attribute_present("val")
|
||||
? is_true(parser().attribute("val")) : true);
|
||||
? is_true(parser().attribute("val"))
|
||||
: true);
|
||||
}
|
||||
else if (current_run_property_element == xml::qname(xmlns, "u"))
|
||||
{
|
||||
|
@ -2931,4 +3037,4 @@ manifest &xlsx_consumer::manifest()
|
|||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namepsace xlnt
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <xlnt/packaging/manifest.hpp>
|
||||
#include <xlnt/utils/path.hpp>
|
||||
#include <xlnt/utils/scoped_enum_hash.hpp>
|
||||
#include <xlnt/utils/serialisation_utils.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/workbook/workbook_view.hpp>
|
||||
#include <xlnt/worksheet/header_footer.hpp>
|
||||
|
@ -45,14 +46,6 @@
|
|||
|
||||
namespace {
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if d is exactly equal to an integer.
|
||||
/// </summary>
|
||||
bool is_integral(double d)
|
||||
{
|
||||
return std::fabs(d - static_cast<double>(static_cast<long long int>(d))) == 0.0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> core_property_namespace(xlnt::core_property type)
|
||||
{
|
||||
using xlnt::core_property;
|
||||
|
@ -2214,9 +2207,46 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x14ac");
|
||||
}
|
||||
|
||||
if (ws.has_page_setup())
|
||||
if (ws.d_->sheet_properties_.is_set())
|
||||
{
|
||||
write_start_element(xmlns, "sheetPr");
|
||||
auto &props = ws.d_->sheet_properties_.get();
|
||||
if (props.sync_horizontal.is_set())
|
||||
{
|
||||
write_attribute("syncHorizontal", props.sync_horizontal.get());
|
||||
}
|
||||
if (props.sync_vertical.is_set())
|
||||
{
|
||||
write_attribute("syncVertical", props.sync_vertical.get());
|
||||
}
|
||||
if (props.sync_ref.is_set())
|
||||
{
|
||||
write_attribute("syncRef", props.sync_ref.get().to_string());
|
||||
}
|
||||
if (props.transition_evaluation.is_set())
|
||||
{
|
||||
write_attribute("transitionEvaluation", props.transition_evaluation.get());
|
||||
}
|
||||
if (props.transition_entry.is_set())
|
||||
{
|
||||
write_attribute("transitionEntry", props.transition_entry.get());
|
||||
}
|
||||
if (props.published.is_set())
|
||||
{
|
||||
write_attribute("published", props.published.get());
|
||||
}
|
||||
if (props.code_name.is_set())
|
||||
{
|
||||
write_attribute("codeName", props.code_name.get());
|
||||
}
|
||||
if (props.filter_mode.is_set())
|
||||
{
|
||||
write_attribute("filterMode", props.filter_mode.get());
|
||||
}
|
||||
if (props.enable_format_condition_calculation.is_set())
|
||||
{
|
||||
write_attribute("enableFormatConditionsCalculation", props.enable_format_condition_calculation.get());
|
||||
}
|
||||
|
||||
write_start_element(xmlns, "outlinePr");
|
||||
write_attribute("summaryBelow", "1");
|
||||
|
@ -2251,13 +2281,17 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_attribute("tabSelected", write_bool(true));
|
||||
}
|
||||
|
||||
write_attribute("workbookViewId", view.id());
|
||||
|
||||
if (view.type() != sheet_view_type::normal)
|
||||
{
|
||||
write_attribute("view", view.type() == sheet_view_type::page_break_preview
|
||||
? "pageBreakPreview" : "pageLayout");
|
||||
}
|
||||
if (view.has_top_left_cell())
|
||||
{
|
||||
write_attribute("topLeftCell", view.top_left_cell().to_string());
|
||||
}
|
||||
|
||||
write_attribute("workbookViewId", view.id());
|
||||
|
||||
if (view.has_pane())
|
||||
{
|
||||
|
@ -2322,7 +2356,11 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_attribute("baseColWidth",
|
||||
format_properties.base_col_width.get());
|
||||
}
|
||||
|
||||
if (format_properties.default_column_width.is_set())
|
||||
{
|
||||
write_attribute("defaultColWidth",
|
||||
format_properties.default_column_width.get());
|
||||
}
|
||||
if (format_properties.default_row_height.is_set())
|
||||
{
|
||||
write_attribute("defaultRowHeight",
|
||||
|
@ -2359,12 +2397,13 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
if (props.width.is_set())
|
||||
{
|
||||
write_attribute("width", (props.width.get() * 7 + 5) / 7);
|
||||
double width = (props.width.get() * 7 + 5) / 7;
|
||||
write_attribute("width", serialize_number_to_string(width));
|
||||
}
|
||||
|
||||
if (props.custom_width)
|
||||
if (props.best_fit)
|
||||
{
|
||||
write_attribute("customWidth", write_bool(true));
|
||||
write_attribute("bestFit", write_bool(true));
|
||||
}
|
||||
|
||||
if (props.style.is_set())
|
||||
|
@ -2377,6 +2416,11 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_attribute("hidden", write_bool(true));
|
||||
}
|
||||
|
||||
if (props.custom_width)
|
||||
{
|
||||
write_attribute("customWidth", write_bool(true));
|
||||
}
|
||||
|
||||
write_end_element(xmlns, "col");
|
||||
}
|
||||
|
||||
|
@ -2404,9 +2448,9 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
// See note for CT_Row, span attribute about block optimization
|
||||
if (first_row_in_block)
|
||||
{
|
||||
first_check_row = first_row;
|
||||
first_check_row = row;
|
||||
// round up to the next multiple of 16
|
||||
last_check_row = (((first_row - 1) / 16) + 1) * 16;
|
||||
last_check_row = ((row / 16) + 1) * 16;
|
||||
}
|
||||
|
||||
for (auto check_row = first_check_row; check_row <= last_check_row; ++check_row)
|
||||
|
@ -2440,18 +2484,19 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
{
|
||||
const auto &props = ws.row_properties(row);
|
||||
|
||||
if (props.style.is_set())
|
||||
{
|
||||
write_attribute("s", props.style.get());
|
||||
}
|
||||
if (props.custom_format.is_set())
|
||||
{
|
||||
write_attribute("customFormat", write_bool(props.custom_format.get()));
|
||||
}
|
||||
|
||||
if (props.height.is_set())
|
||||
{
|
||||
auto height = props.height.get();
|
||||
|
||||
if (std::fabs(height - std::floor(height)) == 0.0)
|
||||
{
|
||||
write_attribute("ht", std::to_string(static_cast<int>(height)) + ".0");
|
||||
}
|
||||
else
|
||||
{
|
||||
write_attribute("ht", height);
|
||||
}
|
||||
write_attribute("ht", serialize_number_to_string(height));
|
||||
}
|
||||
|
||||
if (props.hidden)
|
||||
|
@ -2574,19 +2619,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
|
||||
case cell::type::number:
|
||||
write_start_element(xmlns, "v");
|
||||
|
||||
if (is_integral(cell.value<double>()))
|
||||
{
|
||||
write_characters(static_cast<std::int64_t>(cell.value<double>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss.precision(20);
|
||||
ss << cell.value<double>();
|
||||
write_characters(ss.str());
|
||||
}
|
||||
|
||||
write_characters(serialize_number_to_string(cell.value<double>()));
|
||||
write_end_element(xmlns, "v");
|
||||
break;
|
||||
|
||||
|
@ -2697,14 +2730,49 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
write_end_element(xmlns, "hyperlinks");
|
||||
}
|
||||
|
||||
if (ws.has_page_setup())
|
||||
if (ws.d_->print_options_.is_set())
|
||||
{
|
||||
auto &opts = ws.d_->print_options_.get();
|
||||
write_start_element(xmlns, "printOptions");
|
||||
write_attribute("horizontalCentered", write_bool(ws.page_setup().horizontal_centered()));
|
||||
write_attribute("verticalCentered", write_bool(ws.page_setup().vertical_centered()));
|
||||
if (opts.print_grid_lines.is_set())
|
||||
{
|
||||
write_attribute("gridLines", write_bool(opts.print_grid_lines.get()));
|
||||
}
|
||||
if (opts.grid_lines_set.is_set())
|
||||
{
|
||||
write_attribute("gridLineSet", write_bool(opts.grid_lines_set.get()));
|
||||
}
|
||||
if (opts.print_headings.is_set())
|
||||
{
|
||||
write_attribute("headings", write_bool(opts.print_headings.get()));
|
||||
}
|
||||
if (opts.horizontal_centered.is_set())
|
||||
{
|
||||
write_attribute("horizontalCentered", write_bool(opts.horizontal_centered.get()));
|
||||
}
|
||||
if (opts.vertical_centered.is_set())
|
||||
{
|
||||
write_attribute("verticalCentered", write_bool(opts.vertical_centered.get()));
|
||||
}
|
||||
write_end_element(xmlns, "printOptions");
|
||||
}
|
||||
|
||||
if (ws.has_phonetic_properties())
|
||||
{
|
||||
write_start_element(xmlns, phonetic_pr::Serialised_ID);
|
||||
const auto &ph_props = ws.phonetic_properties();
|
||||
write_attribute("fontId", ph_props.font_id());
|
||||
if (ph_props.has_type())
|
||||
{
|
||||
write_attribute("type", phonetic_pr::type_as_string(ph_props.type()));
|
||||
}
|
||||
if (ph_props.has_alignment())
|
||||
{
|
||||
write_attribute("alignment", phonetic_pr::alignment_as_string(ph_props.alignment()));
|
||||
}
|
||||
write_end_element(xmlns, phonetic_pr::Serialised_ID);
|
||||
}
|
||||
|
||||
if (ws.has_page_margins())
|
||||
{
|
||||
write_start_element(xmlns, "pageMargins");
|
||||
|
@ -2743,11 +2811,21 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
if (ws.has_page_setup())
|
||||
{
|
||||
write_start_element(xmlns, "pageSetup");
|
||||
write_attribute(
|
||||
"orientation", ws.page_setup().orientation() == xlnt::orientation::landscape ? "landscape" : "portrait");
|
||||
write_attribute("paperSize", static_cast<std::size_t>(ws.page_setup().paper_size()));
|
||||
if (ws.page_setup().orientation_.is_set())
|
||||
{
|
||||
write_attribute("orientation", ws.page_setup().orientation_.get());
|
||||
}
|
||||
if (ws.page_setup().horizontal_dpi_.is_set())
|
||||
{
|
||||
write_attribute("horizontalDpi", ws.page_setup().horizontal_dpi_.get());
|
||||
}
|
||||
if (ws.page_setup().vertical_dpi_.is_set())
|
||||
{
|
||||
write_attribute("verticalDpi", ws.page_setup().vertical_dpi_.get());
|
||||
}
|
||||
/*write_attribute("paperSize", static_cast<std::size_t>(ws.page_setup().paper_size()));
|
||||
write_attribute("fitToHeight", write_bool(ws.page_setup().fit_to_height()));
|
||||
write_attribute("fitToWidth", write_bool(ws.page_setup().fit_to_width()));
|
||||
write_attribute("fitToWidth", write_bool(ws.page_setup().fit_to_width()));*/
|
||||
write_end_element(xmlns, "pageSetup");
|
||||
}
|
||||
|
||||
|
@ -2903,6 +2981,11 @@ void xlsx_producer::write_worksheet(const relationship &rel)
|
|||
}
|
||||
}
|
||||
|
||||
if (ws.d_->extension_list_.is_set())
|
||||
{
|
||||
ws.d_->extension_list_.get().serialize(*current_part_serializer_, xmlns);
|
||||
}
|
||||
|
||||
write_end_element(xmlns, "worksheet");
|
||||
|
||||
if (!worksheet_rels.empty())
|
||||
|
|
140
source/packaging/ext_list.cpp
Normal file
140
source/packaging/ext_list.cpp
Normal file
|
@ -0,0 +1,140 @@
|
|||
#include <xlnt/packaging/ext_list.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#include <detail/external/include_libstudxml.hpp>
|
||||
|
||||
namespace {
|
||||
// send elements straight from parser to serialiser without modification
|
||||
// runs until the end of the current open element
|
||||
xlnt::uri roundtrip(xml::parser& p, xml::serializer &s)
|
||||
{
|
||||
xlnt::uri ext_uri;
|
||||
int nest_level = 0;
|
||||
while (nest_level > 0 || (p.peek() != xml::parser::event_type::end_element && p.peek() != xml::parser::event_type::eof))
|
||||
{
|
||||
switch (p.next())
|
||||
{
|
||||
case xml::parser::start_element:
|
||||
{
|
||||
++nest_level;
|
||||
auto attribs = p.attribute_map();
|
||||
s.start_element(p.qname());
|
||||
if (nest_level == 1)
|
||||
{
|
||||
ext_uri = xlnt::uri(attribs.at(xml::qname("uri")).value);
|
||||
}
|
||||
auto current_ns = p.namespace_();
|
||||
p.peek(); // to look into the new namespace
|
||||
auto new_ns = p.namespace_(); // only before attributes?
|
||||
if (new_ns != current_ns)
|
||||
{
|
||||
auto pref = p.prefix();
|
||||
s.namespace_decl(new_ns, pref);
|
||||
}
|
||||
for (auto &ele : attribs)
|
||||
{
|
||||
s.attribute(ele.first.string(), ele.second.value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case xml::parser::end_element:
|
||||
{
|
||||
--nest_level;
|
||||
s.end_element();
|
||||
break;
|
||||
}
|
||||
case xml::parser::start_namespace_decl:
|
||||
{
|
||||
s.namespace_decl(p.namespace_(), p.prefix());
|
||||
break;
|
||||
}
|
||||
case xml::parser::end_namespace_decl:
|
||||
{ // nothing required here
|
||||
break;
|
||||
}
|
||||
case xml::parser::characters:
|
||||
{
|
||||
s.characters(p.value());
|
||||
break;
|
||||
}
|
||||
case xml::parser::eof:
|
||||
return ext_uri;
|
||||
case xml::parser::start_attribute:
|
||||
case xml::parser::end_attribute:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ext_uri;
|
||||
}
|
||||
}
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
ext_list::ext::ext(xml::parser &parser, const std::string& ns)
|
||||
{
|
||||
std::ostringstream serialisation_stream;
|
||||
xml::serializer s(serialisation_stream, "", 0);
|
||||
s.start_element(xml::qname(ns, "wrap")); // wrapper for the xmlns declaration
|
||||
s.namespace_decl(ns, "");
|
||||
extension_ID_ = roundtrip(parser, s);
|
||||
s.end_element(xml::qname(ns, "wrap"));
|
||||
serialised_value_ = serialisation_stream.str();
|
||||
}
|
||||
|
||||
ext_list::ext::ext(const uri &ID, const std::string &serialised)
|
||||
: extension_ID_(ID), serialised_value_(serialised)
|
||||
{}
|
||||
|
||||
void ext_list::ext::serialise(xml::serializer &serialiser, const std::string& ns)
|
||||
{
|
||||
std::istringstream ser(serialised_value_);
|
||||
xml::parser p(ser, "", xml::parser::receive_default);
|
||||
p.next_expect(xml::parser::event_type::start_element, xml::qname(ns, "wrap"));
|
||||
roundtrip(p, serialiser);
|
||||
p.next_expect(xml::parser::event_type::end_element, xml::qname(ns, "wrap"));
|
||||
}
|
||||
|
||||
ext_list::ext_list(xml::parser &parser, const std::string& ns)
|
||||
{
|
||||
// begin with the start element already parsed
|
||||
while (parser.peek() == xml::parser::start_element)
|
||||
{
|
||||
extensions_.push_back(ext(parser, ns));
|
||||
}
|
||||
// end without parsing the end element
|
||||
}
|
||||
|
||||
void ext_list::serialize(xml::serializer &serialiser, const std::string& ns)
|
||||
{
|
||||
serialiser.start_element(ns, "extLst");
|
||||
for (auto &ext : extensions_)
|
||||
{
|
||||
ext.serialise(serialiser, ns);
|
||||
}
|
||||
serialiser.end_element();
|
||||
}
|
||||
|
||||
void ext_list::add_extension(const uri &ID, const std::string &element)
|
||||
{
|
||||
extensions_.push_back(ext{ID, element});
|
||||
}
|
||||
|
||||
bool ext_list::has_extension(const uri &extension_uri) const
|
||||
{
|
||||
return extensions_.end() != std::find_if(extensions_.begin(), extensions_.end(),
|
||||
[&extension_uri](const ext &ext) { return extension_uri == ext.extension_ID_; });
|
||||
}
|
||||
|
||||
const ext_list::ext &ext_list::extension(const uri &extension_uri) const
|
||||
{
|
||||
return *std::find_if(extensions_.begin(), extensions_.end(),
|
||||
[&extension_uri](const ext &ext) { return extension_uri == ext.extension_ID_; });
|
||||
}
|
||||
|
||||
const std::vector<ext_list::ext> &ext_list::extensions() const
|
||||
{
|
||||
return extensions_;
|
||||
}
|
||||
|
||||
}
|
|
@ -78,16 +78,25 @@ path manifest::canonicalize(const std::vector<xlnt::relationship> &rels) const
|
|||
return result;
|
||||
}
|
||||
|
||||
bool manifest::has_relationship(const path &part, relationship_type type) const
|
||||
bool manifest::has_relationship(const path &path, relationship_type type) const
|
||||
{
|
||||
if (relationships_.find(part) == relationships_.end()) return false;
|
||||
|
||||
for (const auto &rel : relationships_.at(part))
|
||||
auto rels = relationships_.find(path);
|
||||
if (rels == relationships_.end())
|
||||
{
|
||||
if (rel.second.type() == type) return true;
|
||||
return false;
|
||||
}
|
||||
return rels->second.end() != std::find_if(rels->second.begin(), rels->second.end(),
|
||||
[type](const std::pair<std::string, xlnt::relationship> &rel) { return rel.second.type() == type; });
|
||||
}
|
||||
|
||||
return false;
|
||||
bool manifest::has_relationship(const path &path, const std::string &rel_id) const
|
||||
{
|
||||
auto rels = relationships_.find(path);
|
||||
if (rels == relationships_.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return rels->second.find(rel_id) != rels->second.end();
|
||||
}
|
||||
|
||||
relationship manifest::relationship(const path &part, relationship_type type) const
|
||||
|
|
|
@ -26,11 +26,14 @@
|
|||
|
||||
#include <xlnt/styles/font.hpp>
|
||||
|
||||
namespace {
|
||||
const std::string Default_Name = "Calibri";
|
||||
constexpr double Default_Size = 12.0;
|
||||
} // namespace
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
font::font()
|
||||
: name_("Calibri"),
|
||||
size_(12.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -140,7 +143,11 @@ font &font::size(double size)
|
|||
|
||||
double font::size() const
|
||||
{
|
||||
return size_.get();
|
||||
if (size_.is_set())
|
||||
{
|
||||
return size_.get();
|
||||
}
|
||||
return Default_Size;
|
||||
}
|
||||
|
||||
bool font::has_name() const
|
||||
|
@ -154,9 +161,13 @@ font &font::name(const std::string &name)
|
|||
return *this;
|
||||
}
|
||||
|
||||
std::string font::name() const
|
||||
const std::string& font::name() const
|
||||
{
|
||||
return name_.get();
|
||||
if (name_.is_set())
|
||||
{
|
||||
return name_.get();
|
||||
}
|
||||
return Default_Name;
|
||||
}
|
||||
|
||||
bool font::has_color() const
|
||||
|
@ -218,7 +229,7 @@ std::size_t font::family() const
|
|||
return family_.get();
|
||||
}
|
||||
|
||||
std::string font::scheme() const
|
||||
const std::string& font::scheme() const
|
||||
{
|
||||
return scheme_.get();
|
||||
}
|
||||
|
@ -241,8 +252,8 @@ bool font::operator==(const font &other) const
|
|||
if (has_color() != other.has_color()) return false;
|
||||
if (has_color() && color() != other.color()) return false;
|
||||
// charset
|
||||
if (has_charset()!= other.has_charset()) return false;
|
||||
if (has_charset() && charset()!= other.charset()) return false;
|
||||
if (has_charset() != other.has_charset()) return false;
|
||||
if (has_charset() && charset() != other.charset()) return false;
|
||||
// modifiers
|
||||
if (bold() != other.bold()) return false;
|
||||
if (italic() != other.italic()) return false;
|
||||
|
|
|
@ -29,12 +29,9 @@ page_setup::page_setup()
|
|||
: break_(xlnt::page_break::none),
|
||||
sheet_state_(xlnt::sheet_state::visible),
|
||||
paper_size_(xlnt::paper_size::letter),
|
||||
orientation_(xlnt::orientation::portrait),
|
||||
fit_to_page_(false),
|
||||
fit_to_height_(false),
|
||||
fit_to_width_(false),
|
||||
horizontal_centered_(false),
|
||||
vertical_centered_(false),
|
||||
scale_(1)
|
||||
{
|
||||
}
|
||||
|
@ -69,16 +66,6 @@ void page_setup::paper_size(xlnt::paper_size paper_size)
|
|||
paper_size_ = paper_size;
|
||||
}
|
||||
|
||||
orientation page_setup::orientation() const
|
||||
{
|
||||
return orientation_;
|
||||
}
|
||||
|
||||
void page_setup::orientation(xlnt::orientation orientation)
|
||||
{
|
||||
orientation_ = orientation;
|
||||
}
|
||||
|
||||
bool page_setup::fit_to_page() const
|
||||
{
|
||||
return fit_to_page_;
|
||||
|
@ -109,26 +96,6 @@ void page_setup::fit_to_width(bool fit_to_width)
|
|||
fit_to_width_ = fit_to_width;
|
||||
}
|
||||
|
||||
void page_setup::horizontal_centered(bool horizontal_centered)
|
||||
{
|
||||
horizontal_centered_ = horizontal_centered;
|
||||
}
|
||||
|
||||
bool page_setup::horizontal_centered() const
|
||||
{
|
||||
return horizontal_centered_;
|
||||
}
|
||||
|
||||
void page_setup::vertical_centered(bool vertical_centered)
|
||||
{
|
||||
vertical_centered_ = vertical_centered;
|
||||
}
|
||||
|
||||
bool page_setup::vertical_centered() const
|
||||
{
|
||||
return vertical_centered_;
|
||||
}
|
||||
|
||||
void page_setup::scale(double scale)
|
||||
{
|
||||
scale_ = scale;
|
||||
|
|
143
source/worksheet/phonetic_pr.cpp
Normal file
143
source/worksheet/phonetic_pr.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
// Copyright (c) 2014-2018 Thomas Fussell
|
||||
//
|
||||
// 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
|
||||
|
||||
#include <xlnt/worksheet/phonetic_pr.hpp>
|
||||
#include <array>
|
||||
namespace {
|
||||
// Order of elements defined by phonetic_pr::Type enum
|
||||
const std::array<std::string, 4> Types{
|
||||
"fullwidthKatakana",
|
||||
"halfwidthKatakana",
|
||||
"Hiragana",
|
||||
"noConversion"};
|
||||
|
||||
// Order of elements defined by phonetic_pr::alignment enum
|
||||
const std::array<std::string, 4> alignments{
|
||||
"Center",
|
||||
"Distributed",
|
||||
"Left",
|
||||
"NoControl"};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace xlnt {
|
||||
/// <summary>
|
||||
/// out of line initialiser for static const member
|
||||
/// </summary>
|
||||
const std::string phonetic_pr::Serialised_ID = "phoneticPr";
|
||||
|
||||
phonetic_pr::phonetic_pr(font_id_t font)
|
||||
: font_id_(font)
|
||||
{
|
||||
}
|
||||
|
||||
void phonetic_pr::serialise(std::ostream &output_stream) const
|
||||
{
|
||||
output_stream << '<' << Serialised_ID << R"( fontID=")" << std::to_string(font_id_) << '"';
|
||||
if (has_type())
|
||||
{
|
||||
output_stream << R"( type=")" << type_as_string(type_.get()) << '"';
|
||||
}
|
||||
if (has_alignment())
|
||||
{
|
||||
output_stream << R"( alignment=")" << alignment_as_string(alignment_.get()) << '"';
|
||||
}
|
||||
output_stream << "/>";
|
||||
}
|
||||
|
||||
phonetic_pr::font_id_t phonetic_pr::font_id() const
|
||||
{
|
||||
return font_id_;
|
||||
}
|
||||
|
||||
void phonetic_pr::font_id(font_id_t font)
|
||||
{
|
||||
font_id_ = font;
|
||||
}
|
||||
|
||||
bool phonetic_pr::has_type() const
|
||||
{
|
||||
return type_.is_set();
|
||||
}
|
||||
|
||||
phonetic_pr::phonetic_type phonetic_pr::type() const
|
||||
{
|
||||
return type_.get();
|
||||
}
|
||||
|
||||
void phonetic_pr::type(phonetic_type type)
|
||||
{
|
||||
type_.set(type);
|
||||
}
|
||||
|
||||
bool phonetic_pr::has_alignment() const
|
||||
{
|
||||
return alignment_.is_set();
|
||||
}
|
||||
|
||||
phonetic_pr::align phonetic_pr::alignment() const
|
||||
{
|
||||
return alignment_.get();
|
||||
}
|
||||
|
||||
void phonetic_pr::alignment(align align)
|
||||
{
|
||||
alignment_.set(align);
|
||||
}
|
||||
|
||||
// serialisation
|
||||
const std::string &phonetic_pr::type_as_string(phonetic_pr::phonetic_type type)
|
||||
{
|
||||
return Types[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
phonetic_pr::phonetic_type phonetic_pr::type_from_string(const std::string &str)
|
||||
{
|
||||
for (std::size_t i = 0; i < Types.size(); ++i)
|
||||
{
|
||||
if (str == Types[i])
|
||||
{
|
||||
return static_cast<phonetic_type>(i);
|
||||
}
|
||||
}
|
||||
return phonetic_type::no_conversion;
|
||||
}
|
||||
|
||||
const std::string &phonetic_pr::alignment_as_string(align type)
|
||||
{
|
||||
return alignments[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
phonetic_pr::align phonetic_pr::alignment_from_string(const std::string &str)
|
||||
{
|
||||
for (std::size_t i = 0; i < alignments.size(); ++i)
|
||||
{
|
||||
if (str == alignments[i])
|
||||
{
|
||||
return static_cast<align>(i);
|
||||
}
|
||||
}
|
||||
return align::no_control;
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
|
@ -26,10 +26,6 @@
|
|||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include <detail/constants.hpp>
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
#include <detail/implementations/workbook_impl.hpp>
|
||||
#include <detail/implementations/worksheet_impl.hpp>
|
||||
#include <xlnt/cell/cell.hpp>
|
||||
#include <xlnt/cell/cell_reference.hpp>
|
||||
#include <xlnt/cell/index_types.hpp>
|
||||
|
@ -46,6 +42,10 @@
|
|||
#include <xlnt/worksheet/range_iterator.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <detail/constants.hpp>
|
||||
#include <detail/implementations/cell_impl.hpp>
|
||||
#include <detail/implementations/workbook_impl.hpp>
|
||||
#include <detail/implementations/worksheet_impl.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -242,25 +242,31 @@ std::string worksheet::title() const
|
|||
|
||||
void worksheet::title(const std::string &title)
|
||||
{
|
||||
if (title.length() > 31)
|
||||
// do no work if we don't need to
|
||||
if (d_->title_ == title)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// excel limits worksheet titles to 31 characters
|
||||
if (title.empty() || title.length() > 31)
|
||||
{
|
||||
throw invalid_sheet_title(title);
|
||||
}
|
||||
|
||||
// invalid characters in a worksheet name
|
||||
if (title.find_first_of("*:/\\?[]") != std::string::npos)
|
||||
{
|
||||
throw invalid_sheet_title(title);
|
||||
}
|
||||
|
||||
auto same_title = std::find_if(workbook().begin(), workbook().end(),
|
||||
[&](worksheet ws) { return ws.title() == title; });
|
||||
|
||||
if (same_title != workbook().end() && *same_title != *this)
|
||||
// try and insert the new name into the worksheets map
|
||||
// if the insert fails, we have a duplicate sheet name
|
||||
auto insert_result = workbook().d_->sheet_title_rel_id_map_.insert(
|
||||
std::make_pair(title, workbook().d_->sheet_title_rel_id_map_[d_->title_]));
|
||||
if (!insert_result.second) // insert failed, duplication detected
|
||||
{
|
||||
throw invalid_sheet_title(title);
|
||||
}
|
||||
|
||||
workbook().d_->sheet_title_rel_id_map_[title] = workbook().d_->sheet_title_rel_id_map_[d_->title_];
|
||||
// if the insert succeeded (i.e. wasn't a duplicate sheet name)
|
||||
// update the worksheet title and remove the old relation
|
||||
workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
|
||||
d_->title_ = title;
|
||||
|
||||
|
@ -284,13 +290,17 @@ void worksheet::freeze_panes(xlnt::cell top_left_cell)
|
|||
|
||||
void worksheet::freeze_panes(const cell_reference &ref)
|
||||
{
|
||||
if (ref == "A1")
|
||||
{
|
||||
unfreeze_panes();
|
||||
return;
|
||||
}
|
||||
if (!has_view())
|
||||
{
|
||||
d_->views_.push_back(sheet_view());
|
||||
}
|
||||
|
||||
auto &primary_view = d_->views_.front();
|
||||
|
||||
if (!primary_view.has_pane())
|
||||
{
|
||||
primary_view.pane(pane());
|
||||
|
@ -300,40 +310,23 @@ void worksheet::freeze_panes(const cell_reference &ref)
|
|||
primary_view.pane().state = pane_state::frozen;
|
||||
|
||||
primary_view.clear_selections();
|
||||
primary_view.add_selection(selection());
|
||||
|
||||
if (ref == "A1")
|
||||
if (ref.column() == "A") // no column is frozen
|
||||
{
|
||||
unfreeze_panes();
|
||||
}
|
||||
else if (ref.column() == "A")
|
||||
{
|
||||
primary_view.add_selection(selection());
|
||||
primary_view.selection(0).pane(pane_corner::bottom_left);
|
||||
primary_view.selection(0).active_cell(ref.make_offset(0, -1)); // cell above
|
||||
primary_view.selection(1).active_cell(ref);
|
||||
primary_view.add_selection(selection(pane_corner::bottom_left, ref));
|
||||
primary_view.pane().active_pane = pane_corner::bottom_left;
|
||||
primary_view.pane().y_split = ref.row() - 1;
|
||||
}
|
||||
else if (ref.row() == 1)
|
||||
else if (ref.row() == 1) // no row is frozen
|
||||
{
|
||||
primary_view.add_selection(selection());
|
||||
primary_view.selection(0).pane(pane_corner::top_right);
|
||||
primary_view.selection(0).active_cell(ref.make_offset(-1, 0)); // cell to the left
|
||||
primary_view.selection(1).active_cell(ref);
|
||||
primary_view.add_selection(selection(pane_corner::top_right, ref));
|
||||
primary_view.pane().active_pane = pane_corner::top_right;
|
||||
primary_view.pane().x_split = ref.column_index() - 1;
|
||||
}
|
||||
else
|
||||
else // column and row is frozen
|
||||
{
|
||||
primary_view.add_selection(selection());
|
||||
primary_view.add_selection(selection());
|
||||
primary_view.selection(0).pane(pane_corner::top_right);
|
||||
primary_view.selection(0).active_cell(ref.make_offset(0, -1)); // cell above
|
||||
primary_view.selection(1).pane(pane_corner::bottom_left);
|
||||
primary_view.selection(1).active_cell(ref.make_offset(-1, 0)); // cell to the left
|
||||
primary_view.selection(2).pane(pane_corner::bottom_right);
|
||||
primary_view.selection(2).active_cell(ref);
|
||||
primary_view.add_selection(selection(pane_corner::top_right, cell_reference(ref.column(), 1)));
|
||||
primary_view.add_selection(selection(pane_corner::bottom_left, cell_reference(1, ref.row())));
|
||||
primary_view.add_selection(selection(pane_corner::bottom_right, ref));
|
||||
primary_view.pane().active_pane = pane_corner::bottom_right;
|
||||
primary_view.pane().x_split = ref.column_index() - 1;
|
||||
primary_view.pane().y_split = ref.row() - 1;
|
||||
|
@ -361,11 +354,12 @@ void worksheet::active_cell(const cell_reference &ref)
|
|||
|
||||
if (!primary_view.has_selections())
|
||||
{
|
||||
primary_view.add_selection(selection());
|
||||
primary_view.add_selection(selection(pane_corner::bottom_right, ref));
|
||||
}
|
||||
else
|
||||
{
|
||||
primary_view.selection(0).active_cell(ref);
|
||||
}
|
||||
|
||||
auto &primary_selection = primary_view.selection(0);
|
||||
primary_selection.active_cell(ref);
|
||||
}
|
||||
|
||||
bool worksheet::has_active_cell() const
|
||||
|
@ -757,6 +751,7 @@ void worksheet::clear_cell(const cell_reference &ref)
|
|||
void worksheet::clear_row(row_t row)
|
||||
{
|
||||
d_->cell_map_.erase(row);
|
||||
d_->row_properties_.erase(row);
|
||||
// TODO: garbage collect newly unreferenced resources such as styles?
|
||||
}
|
||||
|
||||
|
@ -1032,6 +1027,21 @@ void worksheet::register_calc_chain_in_manifest()
|
|||
workbook().register_workbook_part(relationship_type::calculation_chain);
|
||||
}
|
||||
|
||||
bool worksheet::has_phonetic_properties() const
|
||||
{
|
||||
return d_->phonetic_properties_.is_set();
|
||||
}
|
||||
|
||||
const phonetic_pr& worksheet::phonetic_properties() const
|
||||
{
|
||||
return d_->phonetic_properties_.get();
|
||||
}
|
||||
|
||||
void worksheet::phonetic_properties(const phonetic_pr& phonetic_props)
|
||||
{
|
||||
d_->phonetic_properties_.set(phonetic_props);
|
||||
}
|
||||
|
||||
bool worksheet::has_header_footer() const
|
||||
{
|
||||
return d_->header_footer_.is_set();
|
||||
|
@ -1108,7 +1118,7 @@ void worksheet::parent(xlnt::workbook &wb)
|
|||
|
||||
conditional_format worksheet::conditional_format(const range_reference &ref, const condition &when)
|
||||
{
|
||||
return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
|
||||
return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
|
||||
}
|
||||
|
||||
path worksheet::path() const
|
||||
|
|
Binary file not shown.
|
@ -3,28 +3,58 @@
|
|||
#include <cmath>
|
||||
#include <exception>
|
||||
|
||||
#define xlnt_assert(expression) do\
|
||||
{\
|
||||
try { if (expression) break; }\
|
||||
catch (...) {}\
|
||||
throw xlnt::exception("test failed");\
|
||||
#define XLNT_STRINGIFYX(x) #x
|
||||
#define XLNT_STRINGIFY(x) XLNT_STRINGIFYX(x)
|
||||
|
||||
#define xlnt_assert(expression) \
|
||||
do \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
if (expression) break; \
|
||||
} \
|
||||
catch (std::exception & ex) \
|
||||
{ \
|
||||
throw ex; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
} \
|
||||
throw xlnt::exception( \
|
||||
"assert failed at L:" XLNT_STRINGIFY(__LINE__) "\n" XLNT_STRINGIFY(expression)); \
|
||||
} while (false)
|
||||
|
||||
#define xlnt_assert_throws_nothing(expression) do\
|
||||
{\
|
||||
try { expression; break; }\
|
||||
catch (...) {}\
|
||||
throw xlnt::exception("test failed");\
|
||||
#define xlnt_assert_throws_nothing(expression) \
|
||||
do \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
expression; \
|
||||
break; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
} \
|
||||
throw xlnt::exception("assert throws nothing failed at L:" XLNT_STRINGIFY(__LINE__) "\n" XLNT_STRINGIFY(expression)); \
|
||||
} while (false)
|
||||
|
||||
#define xlnt_assert_throws(expression, exception_type) do\
|
||||
{\
|
||||
try { expression; }\
|
||||
catch (exception_type) { break; }\
|
||||
catch (...) {}\
|
||||
throw xlnt::exception("test failed");\
|
||||
#define xlnt_assert_throws(expression, exception_type) \
|
||||
do \
|
||||
{ \
|
||||
try \
|
||||
{ \
|
||||
expression; \
|
||||
} \
|
||||
catch (exception_type) \
|
||||
{ \
|
||||
break; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ \
|
||||
} \
|
||||
throw xlnt::exception("assert throws failed at L:" XLNT_STRINGIFY(__LINE__) "\n" XLNT_STRINGIFY(expression)); \
|
||||
} while (false)
|
||||
|
||||
#define xlnt_assert_equals(left, right) xlnt_assert(left == right)
|
||||
#define xlnt_assert_differs(left, right) xlnt_assert(left != right)
|
||||
#define xlnt_assert_delta(left, right, delta) xlnt_assert(std::abs(left - right) <= delta)
|
||||
#define xlnt_assert_equals(left, right) xlnt_assert((left) == (right))
|
||||
#define xlnt_assert_differs(left, right) xlnt_assert((left) != (right))
|
||||
#define xlnt_assert_delta(left, right, delta) xlnt_assert(std::abs((left) - (right)) <= (delta))
|
||||
|
|
|
@ -39,9 +39,17 @@ public:
|
|||
std::cout << ".";
|
||||
status.tests_passed++;
|
||||
}
|
||||
catch (std::exception &ex)
|
||||
{
|
||||
std::string fail_msg = test.second + " failed with:\n" + std::string(ex.what());
|
||||
std::cout << "*\n"
|
||||
<< fail_msg << '\n';
|
||||
status.tests_failed++;
|
||||
status.failures.push_back(fail_msg);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "*";
|
||||
std::cout << "*\n" << test.second << " failed\n";
|
||||
status.tests_failed++;
|
||||
status.failures.push_back(test.second);
|
||||
}
|
||||
|
|
|
@ -63,11 +63,11 @@ void run_tests()
|
|||
|
||||
void print_summary()
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "\n\n";
|
||||
|
||||
for (auto failure : overall_status.failures)
|
||||
{
|
||||
std::cout << failure << " failed" << std::endl;
|
||||
std::cout << failure << "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ public:
|
|||
xlnt::workbook wb;
|
||||
const auto path = path_helper::test_file("6_encrypted_libre.xlsx");
|
||||
xlnt_assert_throws(wb.load(path, "incorrect"), xlnt::exception);
|
||||
xlnt_assert_throws_nothing(wb.load(path, u8"пароль"));
|
||||
xlnt_assert_throws_nothing(wb.load(path, u8"\u043F\u0430\u0440\u043E\u043B\u044C")); // u8"пароль"
|
||||
}
|
||||
|
||||
void test_decrypt_standard()
|
||||
|
@ -343,16 +343,20 @@ public:
|
|||
{
|
||||
#ifdef _MSC_VER
|
||||
xlnt::workbook wb;
|
||||
const auto path = LSTRING_LITERAL(XLNT_TEST_DATA_DIR) L"/9_unicode_Λ.xlsx";
|
||||
// L"/9_unicode_Λ.xlsx" doesn't use wchar_t(0x039B) for the capital lambda...
|
||||
// L"/9_unicode_\u039B.xlsx" gives the corrct output
|
||||
const auto path = LSTRING_LITERAL(XLNT_TEST_DATA_DIR) L"/9_unicode_\u039B.xlsx"; // L"/9_unicode_Λ.xlsx"
|
||||
wb.load(path);
|
||||
xlnt_assert_equals(wb.active_sheet().cell("A1").value<std::string>(), u8"unicodê!");
|
||||
xlnt_assert_equals(wb.active_sheet().cell("A1").value<std::string>(), u8"un\u00EFc\u00F4d\u0117!"); // u8"unïcôdė!"
|
||||
#endif
|
||||
|
||||
#ifndef __MINGW32__
|
||||
xlnt::workbook wb2;
|
||||
const auto path2 = U8STRING_LITERAL(XLNT_TEST_DATA_DIR) u8"/9_unicode_Λ.xlsx";
|
||||
// u8"/9_unicode_Λ.xlsx" doesn't use 0xc3aa for the capital lambda...
|
||||
// u8"/9_unicode_\u039B.xlsx" gives the corrct output
|
||||
const auto path2 = U8STRING_LITERAL(XLNT_TEST_DATA_DIR) u8"/9_unicode_\u039B.xlsx"; // u8"/9_unicode_Λ.xlsx"
|
||||
wb2.load(path2);
|
||||
xlnt_assert_equals(wb2.active_sheet().cell("A1").value<std::string>(), u8"unicodê!");
|
||||
xlnt_assert_equals(wb2.active_sheet().cell("A1").value<std::string>(), u8"un\u00EFc\u00F4d\u0117!"); // u8"unïcôdė!"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -393,7 +397,6 @@ public:
|
|||
xlnt_assert(ws1.cell("A7").has_hyperlink());
|
||||
xlnt_assert_equals(ws1.cell("A7").value<std::string>(), "mailto:invalid@example.com?subject=important");
|
||||
xlnt_assert_equals(ws1.cell("A7").hyperlink().url(), "mailto:invalid@example.com?subject=important");
|
||||
|
||||
}
|
||||
|
||||
void test_read_formulae()
|
||||
|
@ -471,11 +474,11 @@ public:
|
|||
xlnt_assert_equals(ws.cell("B4").value<std::string>(), "B4");
|
||||
xlnt_assert_equals(ws.cell("D4").value<std::string>(), "D4");
|
||||
|
||||
xlnt_assert_equals(ws.row_properties(1).height.get(), 100);
|
||||
xlnt_assert_equals(ws.row_properties(1).height.get(), 99.95);
|
||||
xlnt_assert(!ws.row_properties(2).height.is_set());
|
||||
xlnt_assert_equals(ws.row_properties(3).height.get(), 100);
|
||||
xlnt_assert_equals(ws.row_properties(3).height.get(), 99.95);
|
||||
xlnt_assert(!ws.row_properties(4).height.is_set());
|
||||
xlnt_assert_equals(ws.row_properties(5).height.get(), 100);
|
||||
xlnt_assert_equals(ws.row_properties(5).height.get(), 99.95);
|
||||
|
||||
auto width = ((16.0 * 7) - 5) / 7;
|
||||
|
||||
|
@ -520,13 +523,13 @@ public:
|
|||
ws.row_properties(i).dy_descent = 0.2;
|
||||
}
|
||||
|
||||
ws.row_properties(1).height = 100;
|
||||
ws.row_properties(1).height = 99.95;
|
||||
ws.row_properties(1).custom_height = true;
|
||||
|
||||
ws.row_properties(3).height = 100;
|
||||
ws.row_properties(3).height = 99.95;
|
||||
ws.row_properties(3).custom_height = true;
|
||||
|
||||
ws.row_properties(5).height = 100;
|
||||
ws.row_properties(5).height = 99.95;
|
||||
ws.row_properties(5).custom_height = true;
|
||||
|
||||
auto width = ((16.0 * 7) - 5) / 7;
|
||||
|
@ -540,9 +543,6 @@ public:
|
|||
ws.column_properties("E").width = width;
|
||||
ws.column_properties("E").custom_width = true;
|
||||
|
||||
wb.default_slicer_style("SlicerStyleLight1");
|
||||
wb.enable_known_fonts();
|
||||
|
||||
xlnt_assert(workbook_matches_file(wb,
|
||||
path_helper::test_file("13_custom_heights_widths.xlsx")));
|
||||
}
|
||||
|
@ -610,7 +610,9 @@ public:
|
|||
|
||||
void test_round_trip_rw_unicode()
|
||||
{
|
||||
xlnt_assert(round_trip_matches_rw(path_helper::test_file(u8"9_unicode_Λ.xlsx")));
|
||||
// u8"/9_unicode_Λ.xlsx" doesn't use 0xc3aa for the capital lambda...
|
||||
// u8"/9_unicode_\u039B.xlsx" gives the corrct output
|
||||
xlnt_assert(round_trip_matches_rw(path_helper::test_file(u8"9_unicode_\u039B.xlsx")));
|
||||
}
|
||||
|
||||
void test_round_trip_rw_comments_hyperlinks_formulae()
|
||||
|
@ -640,7 +642,7 @@ public:
|
|||
|
||||
void test_round_trip_rw_encrypted_libre()
|
||||
{
|
||||
xlnt_assert(round_trip_matches_rw(path_helper::test_file("6_encrypted_libre.xlsx"), u8"пароль"));
|
||||
xlnt_assert(round_trip_matches_rw(path_helper::test_file("6_encrypted_libre.xlsx"), u8"\u043F\u0430\u0440\u043E\u043B\u044C")); // u8"пароль"
|
||||
}
|
||||
|
||||
void test_round_trip_rw_encrypted_standard()
|
||||
|
|
|
@ -44,9 +44,9 @@ public:
|
|||
ps.paper_size(xlnt::paper_size::executive);
|
||||
xlnt_assert_equals(ps.paper_size(), xlnt::paper_size::executive);
|
||||
|
||||
xlnt_assert_equals(ps.orientation(), xlnt::orientation::portrait);
|
||||
ps.orientation(xlnt::orientation::landscape);
|
||||
xlnt_assert_equals(ps.orientation(), xlnt::orientation::landscape);
|
||||
xlnt_assert(!ps.orientation_.is_set());
|
||||
ps.orientation_.set(xlnt::orientation::landscape);
|
||||
xlnt_assert_equals(ps.orientation_.get(), xlnt::orientation::landscape);
|
||||
|
||||
xlnt_assert(!ps.fit_to_page());
|
||||
ps.fit_to_page(true);
|
||||
|
@ -59,13 +59,5 @@ public:
|
|||
xlnt_assert(!ps.fit_to_width());
|
||||
ps.fit_to_width(true);
|
||||
xlnt_assert(ps.fit_to_width());
|
||||
|
||||
xlnt_assert(!ps.horizontal_centered());
|
||||
ps.horizontal_centered(true);
|
||||
xlnt_assert(ps.horizontal_centered());
|
||||
|
||||
xlnt_assert(!ps.vertical_centered());
|
||||
ps.vertical_centered(true);
|
||||
xlnt_assert(ps.vertical_centered());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include <helpers/test_suite.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/header_footer.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <helpers/test_suite.hpp>
|
||||
|
||||
class worksheet_test_suite : public test_suite
|
||||
{
|
||||
|
@ -101,6 +101,7 @@ public:
|
|||
register_test(test_view_properties_serialization);
|
||||
register_test(test_clear_cell);
|
||||
register_test(test_clear_row);
|
||||
register_test(test_set_title);
|
||||
}
|
||||
|
||||
void test_new_worksheet()
|
||||
|
@ -224,12 +225,44 @@ public:
|
|||
{
|
||||
xlnt::workbook wb;
|
||||
auto ws = wb.active_sheet();
|
||||
ws.cell("A1").hyperlink("http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink().url(), "http://test.com");
|
||||
xlnt_assert_equals(ws.cell("A1").value<std::string>(), "");
|
||||
ws.cell("A1").value("test");
|
||||
xlnt_assert_equals("test", ws.cell("A1").value<std::string>());
|
||||
xlnt_assert_equals(ws.cell("A1").hyperlink().url(), "http://test.com");
|
||||
std::string test_link = "http://test.com";
|
||||
xlnt::cell_reference test_cell("A1");
|
||||
ws.cell(test_cell).hyperlink(test_link);
|
||||
// when a hyperlink is added to an empty cell, the display text becomes == to the link
|
||||
xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link);
|
||||
xlnt_assert_equals(ws.cell(test_cell).value<std::string>(), test_link);
|
||||
// if the display value changes, the hyperlink remains the same
|
||||
std::string test_string = "test";
|
||||
ws.cell(test_cell).value(test_string);
|
||||
xlnt_assert_equals(test_string, ws.cell(test_cell).value<std::string>());
|
||||
xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link);
|
||||
// changing the link doesn't change the cell value
|
||||
std::string test_link2 = "http://test-123.com";
|
||||
ws.cell(test_cell).hyperlink(test_link2);
|
||||
xlnt_assert_equals(test_string, ws.cell(test_cell).value<std::string>());
|
||||
xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link2);
|
||||
// and we can edit both value and hyperlink together
|
||||
std::string test_string3 = "123test";
|
||||
std::string test_link3 = "http://123-test.com";
|
||||
ws.cell(test_cell).hyperlink(test_link3, test_string3);
|
||||
xlnt_assert_equals(test_string3, ws.cell(test_cell).value<std::string>());
|
||||
xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link3);
|
||||
// hyperlinks can also be applied to cells with non-string values
|
||||
int numeric_test_val = 123;
|
||||
std::string test_link4 = "http://test-numeric.com";
|
||||
xlnt::cell_reference numeric_test_cell("B1");
|
||||
ws.cell(numeric_test_cell).value(numeric_test_val);
|
||||
ws.cell(numeric_test_cell).hyperlink(test_link4);
|
||||
xlnt_assert_equals(ws.cell(numeric_test_cell).hyperlink().url(), test_link4);
|
||||
xlnt_assert_equals(ws.cell(numeric_test_cell).value<int>(), numeric_test_val);
|
||||
// and there should be no issues if two cells use the same hyperlink
|
||||
ws.cell(numeric_test_cell).hyperlink(test_link3); // still in use on 'A1'
|
||||
// 'A1'
|
||||
xlnt_assert_equals(test_string3, ws.cell(test_cell).value<std::string>());
|
||||
xlnt_assert_equals(ws.cell(test_cell).hyperlink().url(), test_link3);
|
||||
// 'B1'
|
||||
xlnt_assert_equals(ws.cell(numeric_test_cell).hyperlink().url(), test_link3);
|
||||
xlnt_assert_equals(ws.cell(numeric_test_cell).value<int>(), numeric_test_val);
|
||||
}
|
||||
|
||||
void test_rows()
|
||||
|
@ -376,7 +409,6 @@ public:
|
|||
xlnt_assert(!merged.contains("O1"));
|
||||
}
|
||||
|
||||
|
||||
void test_merged_cell_ranges()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
|
@ -391,7 +423,7 @@ public:
|
|||
ws.cell("A1").value(1);
|
||||
ws.cell("D4").value(16);
|
||||
ws.merge_cells("A1:D4");
|
||||
std::vector<xlnt::range_reference> expected = { xlnt::range_reference("A1:D4") };
|
||||
std::vector<xlnt::range_reference> expected = {xlnt::range_reference("A1:D4")};
|
||||
xlnt_assert_equals(ws.merged_ranges(), expected);
|
||||
xlnt_assert(!ws.cell("D4").has_value());
|
||||
}
|
||||
|
@ -460,10 +492,13 @@ public:
|
|||
ws.freeze_panes("A4");
|
||||
|
||||
auto view = ws.view();
|
||||
xlnt_assert_equals(view.selections().size(), 2);
|
||||
xlnt_assert_equals(view.selections()[0].active_cell(), "A3");
|
||||
xlnt_assert_equals(view.selections().size(), 1);
|
||||
// pane is the corner of the worksheet that this selection extends to
|
||||
// active cell is the last selected cell in the selection
|
||||
// sqref is the last selected block in the selection
|
||||
xlnt_assert_equals(view.selections()[0].pane(), xlnt::pane_corner::bottom_left);
|
||||
xlnt_assert_equals(view.selections()[0].sqref(), "A1");
|
||||
xlnt_assert_equals(view.selections()[0].active_cell(), "A4");
|
||||
xlnt_assert_equals(view.selections()[0].sqref(), "A4");
|
||||
xlnt_assert_equals(view.pane().active_pane, xlnt::pane_corner::bottom_left);
|
||||
xlnt_assert_equals(view.pane().state, xlnt::pane_state::frozen);
|
||||
xlnt_assert_equals(view.pane().top_left_cell.get(), "A4");
|
||||
|
@ -477,10 +512,13 @@ public:
|
|||
ws.freeze_panes("D1");
|
||||
|
||||
auto view = ws.view();
|
||||
xlnt_assert_equals(view.selections().size(), 2);
|
||||
xlnt_assert_equals(view.selections()[0].active_cell(), "C1");
|
||||
xlnt_assert_equals(view.selections().size(), 1);
|
||||
// pane is the corner of the worksheet that this selection extends to
|
||||
// active cell is the last selected cell in the selection
|
||||
// sqref is the last selected block in the selection
|
||||
xlnt_assert_equals(view.selections()[0].pane(), xlnt::pane_corner::top_right);
|
||||
xlnt_assert_equals(view.selections()[0].sqref(), "A1");
|
||||
xlnt_assert_equals(view.selections()[0].active_cell(), "D1");
|
||||
xlnt_assert_equals(view.selections()[0].sqref(), "D1");
|
||||
xlnt_assert_equals(view.pane().active_pane, xlnt::pane_corner::top_right);
|
||||
xlnt_assert_equals(view.pane().state, xlnt::pane_state::frozen);
|
||||
xlnt_assert_equals(view.pane().top_left_cell.get(), "D1");
|
||||
|
@ -495,11 +533,18 @@ public:
|
|||
|
||||
auto view = ws.view();
|
||||
xlnt_assert_equals(view.selections().size(), 3);
|
||||
// pane is the corner of the worksheet that this selection extends to
|
||||
// active cell is the last selected cell in the selection
|
||||
// sqref is the last selected block in the selection
|
||||
xlnt_assert_equals(view.selections()[0].pane(), xlnt::pane_corner::top_right);
|
||||
xlnt_assert_equals(view.selections()[0].active_cell(), "D1");
|
||||
xlnt_assert_equals(view.selections()[0].sqref(), "D1");
|
||||
xlnt_assert_equals(view.selections()[1].pane(), xlnt::pane_corner::bottom_left);
|
||||
xlnt_assert_equals(view.selections()[2].active_cell(), "D4");
|
||||
xlnt_assert_equals(view.selections()[1].active_cell(), "A4");
|
||||
xlnt_assert_equals(view.selections()[1].sqref(), "A4");
|
||||
xlnt_assert_equals(view.selections()[2].pane(), xlnt::pane_corner::bottom_right);
|
||||
xlnt_assert_equals(view.selections()[2].sqref(), "A1");
|
||||
xlnt_assert_equals(view.selections()[2].active_cell(), "D4");
|
||||
xlnt_assert_equals(view.selections()[2].sqref(), "D4");
|
||||
xlnt_assert_equals(view.pane().active_pane, xlnt::pane_corner::bottom_right);
|
||||
xlnt_assert_equals(view.pane().state, xlnt::pane_state::frozen);
|
||||
xlnt_assert_equals(view.pane().top_left_cell.get(), "D4");
|
||||
|
@ -825,7 +870,7 @@ public:
|
|||
xlnt::header_footer hf;
|
||||
using hf_loc = xlnt::header_footer::location;
|
||||
|
||||
for (auto location : { hf_loc::left, hf_loc::center, hf_loc::right })
|
||||
for (auto location : {hf_loc::left, hf_loc::center, hf_loc::right})
|
||||
{
|
||||
xlnt_assert(!hf.has_header(location));
|
||||
xlnt_assert(!hf.has_odd_even_header(location));
|
||||
|
@ -850,7 +895,7 @@ public:
|
|||
xlnt::header_footer hf;
|
||||
using hf_loc = xlnt::header_footer::location;
|
||||
|
||||
for (auto location : { hf_loc::left, hf_loc::center, hf_loc::right })
|
||||
for (auto location : {hf_loc::left, hf_loc::center, hf_loc::right})
|
||||
{
|
||||
xlnt_assert(!hf.has_footer(location));
|
||||
xlnt_assert(!hf.has_odd_even_footer(location));
|
||||
|
@ -1186,11 +1231,11 @@ public:
|
|||
xlnt_assert_equals(ws.highest_row(), last_row);
|
||||
|
||||
wb.save("temp.xlsx");
|
||||
|
||||
|
||||
xlnt::workbook wb2;
|
||||
wb2.load("temp.xlsx");
|
||||
auto ws2 = wb2.active_sheet();
|
||||
|
||||
|
||||
xlnt_assert_equals(ws2.calculate_dimension().height(), height);
|
||||
xlnt_assert(!ws2.has_cell(xlnt::cell_reference(1, last_row)));
|
||||
}
|
||||
|
@ -1212,12 +1257,42 @@ public:
|
|||
xlnt_assert_equals(ws.highest_row(), last_row - 1);
|
||||
|
||||
wb.save("temp.xlsx");
|
||||
|
||||
|
||||
xlnt::workbook wb2;
|
||||
wb2.load("temp.xlsx");
|
||||
auto ws2 = wb2.active_sheet();
|
||||
|
||||
|
||||
xlnt_assert_equals(ws2.calculate_dimension().height(), height - 1);
|
||||
xlnt_assert(!ws2.has_cell(xlnt::cell_reference(1, last_row)));
|
||||
}
|
||||
|
||||
void test_set_title()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto ws1 = wb.active_sheet();
|
||||
// empty titles are invalid
|
||||
xlnt_assert_throws(ws1.title(""), xlnt::invalid_sheet_title);
|
||||
// titles longer than 31 chars are invalid
|
||||
std::string test_long_title(32, 'a');
|
||||
xlnt_assert(test_long_title.size() > 31);
|
||||
xlnt_assert_throws(ws1.title(test_long_title), xlnt::invalid_sheet_title);
|
||||
// titles containing any of the following characters are invalid
|
||||
std::string invalid_chars = "*:/\\?[]";
|
||||
for (char &c : invalid_chars)
|
||||
{
|
||||
std::string invalid_char = std::string("Sheet") + c;
|
||||
xlnt_assert_throws(ws1.title(invalid_char), xlnt::invalid_sheet_title);
|
||||
}
|
||||
// duplicate names are invalid
|
||||
auto ws2 = wb.create_sheet();
|
||||
xlnt_assert_throws(ws2.title(ws1.title()), xlnt::invalid_sheet_title);
|
||||
xlnt_assert_throws(ws1.title(ws2.title()), xlnt::invalid_sheet_title);
|
||||
// naming as self is valid and is ignored
|
||||
auto ws1_title = ws1.title();
|
||||
auto ws2_title = ws2.title();
|
||||
xlnt_assert_throws_nothing(ws1.title(ws1.title()));
|
||||
xlnt_assert_throws_nothing(ws2.title(ws2.title()));
|
||||
xlnt_assert(ws1_title == ws1.title());
|
||||
xlnt_assert(ws2_title == ws2.title());
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user