keep cleaning up iterators, documenting classes, and moving implementations to source files

This commit is contained in:
Thomas Fussell 2015-11-20 20:41:32 -05:00
parent 47b81a83de
commit acfb5c642b
82 changed files with 2073 additions and 1340 deletions

View File

@ -27,9 +27,9 @@
#include <string>
#include <unordered_map>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/cell_type.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/xlnt_config.hpp> // for XLNT_CLASS, XLNT_FUNCTION
#include <xlnt/cell/cell_type.hpp> // for cell_type
#include <xlnt/cell/index_types.hpp> // for column_t, row_t
namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <utility>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
namespace xlnt {

View File

@ -29,6 +29,11 @@
namespace xlnt {
/// <summary>
/// Default types in an OOXML package are identified by their extension.
/// All files in the package with this extension will be assigned the given
/// content type unless an override type for the exact file is provided.
/// </summary>
class XLNT_CLASS default_type
{
public:

View File

@ -31,7 +31,7 @@
namespace xlnt {
/// <summary>
/// High-level properties of the document.
/// High-level properties of the OOXML document.
/// </summary>
class XLNT_CLASS document_properties
{

View File

@ -32,6 +32,10 @@
namespace xlnt {
/// <summary>
/// The manifest keeps track of all files the OOXML package and
/// their type.
/// </summary>
class XLNT_CLASS manifest
{
public:

View File

@ -29,6 +29,10 @@
namespace xlnt {
/// <summary>
/// An override_type applies a different content type to a file which
/// already has a default content type for its extension.
/// </summary>
class XLNT_CLASS override_type
{
public:

View File

@ -67,134 +67,41 @@ class XLNT_CLASS relationship
custom_xml
};
static type type_from_string(const std::string &type_string)
{
if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties")
{
return type::extended_properties;
}
else if (type_string == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties")
{
return type::core_properties;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
{
return type::office_document;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet")
{
return type::worksheet;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")
{
return type::shared_strings;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles")
{
return type::styles;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")
{
return type::theme;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
{
return type::hyperlink;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet")
{
return type::chartsheet;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml")
{
return type::custom_xml;
}
return type::invalid;
}
static std::string type_to_string(type t)
{
switch (t)
{
case type::extended_properties:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
case type::core_properties:
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
case type::office_document:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
case type::worksheet:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
case type::shared_strings:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
case type::styles:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
case type::theme:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
case type::hyperlink:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
case type::chartsheet:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
case type::custom_xml:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
default:
return "??";
}
}
static type type_from_string(const std::string &type_string);
static std::string type_to_string(type t);
relationship();
relationship(const std::string &t, const std::string &r_id = "", const std::string &target_uri = "")
: relationship(type_from_string(t), r_id, target_uri)
{
}
relationship(const std::string &t, const std::string &r_id = "", const std::string &target_uri = "");
relationship(type t, const std::string &r_id = "", const std::string &target_uri = "");
/// <summary>
/// gets a string that identifies the relationship.
/// </summary>
std::string get_id() const
{
return id_;
}
std::string get_id() const;
/// <summary>
/// gets the URI of the package or part that owns the relationship.
/// </summary>
std::string get_source_uri() const
{
return source_uri_;
}
std::string get_source_uri() const;
/// <summary>
/// gets a value that indicates whether the target of the relationship is or External to the Package.
/// </summary>
target_mode get_target_mode() const
{
return target_mode_;
}
target_mode get_target_mode() const;
/// <summary>
/// gets the URI of the target resource of the relationship.
/// </summary>
std::string get_target_uri() const
{
return target_uri_;
}
std::string get_target_uri() const;
type get_type() const
{
return type_;
}
std::string get_type_string() const
{
return type_to_string(type_);
}
friend bool operator==(const relationship &left, const relationship &right)
{
return left.type_ == right.type_ && left.id_ == right.id_ && left.source_uri_ == right.source_uri_ &&
left.target_uri_ == right.target_uri_ && left.target_mode_ == right.target_mode_;
}
type get_type() const;
std::string get_type_string() const;
bool operator==(const relationship &rhs) const;
private:
type type_;

View File

@ -33,6 +33,9 @@ namespace xlnt {
class xml_document;
/// <summary>
/// Manages converting comments to and from XML.
/// </summary>
class XLNT_CLASS comment_serializer
{
comment_serializer(worksheet sheet);

View File

@ -32,6 +32,9 @@ namespace xlnt {
class manifest;
class xml_document;
/// <summary>
/// Manages converting a manifest to and from XML.
/// </summary>
class XLNT_CLASS manifest_serializer
{
public:

View File

@ -32,6 +32,9 @@ namespace xlnt {
class xml_document;
/// <summary>
/// Manages converting a set of shared strings to and from XML.
/// </summary>
class XLNT_CLASS shared_strings_serializer
{
public:

View File

@ -32,6 +32,9 @@ namespace xlnt {
class theme;
class xml_document;
/// <summary>
/// Manages converting a theme to and from XML.
/// </summary>
class XLNT_CLASS theme_serializer
{
public:

View File

@ -39,6 +39,9 @@ class zip_file;
class xml_document;
class xml_node;
/// <summary>
/// Manages converting workbook to and from XML.
/// </summary>
class XLNT_CLASS workbook_serializer
{
public:

View File

@ -36,6 +36,9 @@ class workbook;
class worksheet;
class xml_document;
/// <summary>
/// Manages converting a worksheet to and from XML.
/// </summary>
class XLNT_CLASS worksheet_serializer
{
public:

View File

@ -34,6 +34,9 @@ namespace detail { struct xml_document_impl; }
class xml_node;
class xml_serializer;
/// <summary>
/// Abstracts an XML document from a particular implementation.
/// </summary>
class XLNT_CLASS xml_document
{
public:

View File

@ -33,6 +33,9 @@ namespace detail { struct xml_node_impl; }
class xml_document;
/// <summary>
/// Abstracts an XML node from a particular implementation.
/// </summary>
class XLNT_CLASS xml_node
{
public:

View File

@ -31,6 +31,9 @@ namespace xlnt {
class xml_document;
class xml_node;
/// <summary>
/// Converts XML documents to and from raw strings.
/// </summary>
class XLNT_CLASS xml_serializer
{
public:

View File

@ -25,6 +25,8 @@
#include <xlnt/xlnt_config.hpp>
#include <xlnt/utils/hash_combine.hpp>
#include <xlnt/styles/horizontal_alignment.hpp>
#include <xlnt/styles/vertical_alignment.hpp>
namespace xlnt {
@ -34,82 +36,25 @@ namespace xlnt {
class XLNT_CLASS alignment
{
public:
enum class horizontal_alignment
{
none,
general,
left,
right,
center,
center_continuous,
justify
};
bool get_wrap_text() const;
enum class vertical_alignment
{
none,
bottom,
top,
center,
justify
};
void set_wrap_text(bool wrap_text);
bool get_wrap_text() const
{
return wrap_text_;
}
bool has_horizontal() const;
void set_wrap_text(bool wrap_text)
{
wrap_text_ = wrap_text;
}
horizontal_alignment get_horizontal() const;
bool has_horizontal() const
{
return horizontal_ != horizontal_alignment::none;
}
void set_horizontal(horizontal_alignment horizontal);
horizontal_alignment get_horizontal() const
{
return horizontal_;
}
bool has_vertical() const;
void set_horizontal(horizontal_alignment horizontal)
{
horizontal_ = horizontal;
}
vertical_alignment get_vertical() const;
bool has_vertical() const
{
return vertical_ != vertical_alignment::none;
}
void set_vertical(vertical_alignment vertical);
vertical_alignment get_vertical() const
{
return vertical_;
}
bool operator==(const alignment &other) const;
void set_vertical(vertical_alignment vertical)
{
vertical_ = vertical;
}
bool operator==(const alignment &other) const
{
return hash() == other.hash();
}
std::size_t hash() const
{
std::size_t seed = 0;
hash_combine(seed, wrap_text_);
hash_combine(seed, shrink_to_fit_);
hash_combine(seed, static_cast<std::size_t>(horizontal_));
hash_combine(seed, static_cast<std::size_t>(vertical_));
hash_combine(seed, text_rotation_);
hash_combine(seed, indent_);
return seed;
}
std::size_t hash() const;
private:
horizontal_alignment horizontal_ = horizontal_alignment::none;

View File

@ -27,19 +27,15 @@
#include <functional>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/styles/diagonal_direction.hpp>
#include <xlnt/styles/side.hpp>
#include <xlnt/utils/hash_combine.hpp>
namespace xlnt {
enum class XLNT_CLASS diagonal_direction
{
none,
up,
down,
both
};
/// <summary>
/// Describes the border style of a particular cell.
/// </summary>
class XLNT_CLASS border
{
public:
@ -70,36 +66,9 @@ class XLNT_CLASS border
diagonal_direction diagonal_direction_ = diagonal_direction::none;
bool operator==(const border &other) const
{
return hash() == other.hash();
}
bool operator==(const border &other) const;
std::size_t hash() const
{
std::size_t seed = 0;
hash_combine(seed, start_assigned);
if (start_assigned) hash_combine(seed, start.hash());
hash_combine(seed, end_assigned);
if (end_assigned) hash_combine(seed, end.hash());
hash_combine(seed, left_assigned);
if (left_assigned) hash_combine(seed, left.hash());
hash_combine(seed, right_assigned);
if (right_assigned) hash_combine(seed, right.hash());
hash_combine(seed, top_assigned);
if (top_assigned) hash_combine(seed, top.hash());
hash_combine(seed, bottom_assigned);
if (bottom_assigned) hash_combine(seed, bottom.hash());
hash_combine(seed, diagonal_assigned);
if (diagonal_assigned) hash_combine(seed, diagonal.hash());
hash_combine(seed, vertical_assigned);
if (vertical_assigned) hash_combine(seed, vertical.hash());
hash_combine(seed, horizontal_assigned);
if (horizontal_assigned) hash_combine(seed, horizontal.hash());
return seed;
}
std::size_t hash() const;
};
} // namespace xlnt

View File

@ -30,9 +30,15 @@
namespace xlnt {
/// <summary>
/// Colors can be applied to many parts of a cell's style.
/// </summary>
class XLNT_CLASS color
{
public:
public:
/// <summary>
/// Some colors are references to colors rather than having a particular RGB value.
/// </summary>
enum class type
{
indexed,

View File

@ -0,0 +1,43 @@
// Copyright (c) 2014-2015 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#pragma once
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
/// <summary>
/// Cells can have borders that go from the top-left to bottom-right
/// or from the top-right to bottom-left, or both, or neither.
/// Used by style->border.
/// </summary>
enum class XLNT_CLASS diagonal_direction
{
none,
up,
down,
both
};
} // namespace xlnt

View File

@ -29,6 +29,9 @@
namespace xlnt {
/// <summary>
/// Describes the fill style of a particular cell.
/// </summary>
class XLNT_CLASS fill
{
public:

View File

@ -33,6 +33,9 @@ namespace xlnt {
class style;
/// <summary>
/// Describes the font style of a particular cell.
/// </summary>
class XLNT_CLASS font
{
public:

View File

@ -0,0 +1,44 @@
// Copyright (c) 2014-2015 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#pragma once
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
/// <summary>
/// Text can be aligned horizontally in these enumerated ways.
/// </summary>
enum class XLNT_CLASS horizontal_alignment
{
none,
general,
left,
right,
center,
center_continuous,
justify
};
} // namespace xlnt

View File

@ -28,6 +28,9 @@
namespace xlnt {
/// <summary>
/// A named style is simply a style that can be referred to by name rather than by index.
/// </summary>
class XLNT_CLASS named_style
{
public:

View File

@ -31,6 +31,11 @@
namespace xlnt {
enum class calendar;
/// <summary>
/// Describes the number formatting applied to text and numbers within a certain cell.
/// </summary>
class XLNT_CLASS number_format
{
public:
@ -81,33 +86,19 @@ class XLNT_CLASS number_format
std::string get_format_string() const;
bool has_id() const
{
return id_set_;
}
void set_id(std::size_t id)
{
id_ = id;
id_set_ = true;
}
bool has_id() const;
void set_id(std::size_t id);
std::size_t get_id() const
{
if(!id_set_)
{
throw std::runtime_error("number format doesn't have an id");
}
return id_;
}
std::size_t get_id() const;
std::size_t hash() const;
std::string format(const std::string &text) const;
std::string format(long double number, calendar base_date) const;
bool is_date_format() const;
bool operator==(const number_format &other) const
{
return hash() == other.hash();
}
bool operator==(const number_format &other) const;
private:
bool id_set_;

View File

@ -30,6 +30,9 @@
namespace xlnt {
/// <summary>
/// Describes the protection style of a particular cell.
/// </summary>
class XLNT_CLASS protection
{
public:

View File

@ -48,6 +48,9 @@ enum class XLNT_CLASS border_style
thin
};
/// <summary>
/// Describes the one of the sides of a border of a particular cell.
/// </summary>
class XLNT_CLASS side
{
public:

View File

@ -35,6 +35,9 @@ namespace xlnt {
class workbook;
/// <summary>
/// Describes the entirety of the styling of a particular cell.
/// </summary>
class XLNT_CLASS style
{
public:

View File

@ -0,0 +1,42 @@
// Copyright (c) 2014-2015 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#pragma once
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
/// <summary>
/// Text can be aligned vertically in these enumerated ways.
/// </summary>
enum class XLNT_CLASS vertical_alignment
{
none,
bottom,
top,
center,
justify
};
} // namespace xlnt

View File

@ -25,7 +25,7 @@
#include <stdexcept>
#include <xlnt/cell/types.hpp>
#include <xlnt/xlnt_config.hpp>
namespace xlnt {

View File

@ -27,7 +27,7 @@
#include <string>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
namespace xlnt {

View File

@ -29,6 +29,9 @@
namespace xlnt {
/// <summary>
/// A datetime is a combination of a date and a time.
/// </summary>
struct XLNT_CLASS datetime
{
/// <summary>

View File

@ -23,6 +23,8 @@
// @author: see AUTHORS file
#pragma once
// An shortcut for including all possible exceptions in xlnt.
#include <xlnt/utils/attribute_error.hpp>
#include <xlnt/utils/cell_coordinates_exception.hpp>
#include <xlnt/utils/column_string_index_exception.hpp>

View File

@ -35,6 +35,9 @@
namespace xlnt {
// TODO: Can this be in source->detail, or must it be in a header?
/// <summary>
/// Return a value by combining the hashed value of v (using std::hash) with seed.
/// </summary>
template <class T>
inline void XLNT_FUNCTION hash_combine(std::size_t &seed, const T &v)
{

View File

@ -31,7 +31,7 @@
namespace xlnt {
/// <summary>
/// Error for trying to open a non-ooxml file.
/// Error for trying to open a non-OOXML file.
/// </summary>
class XLNT_CLASS invalid_file_exception : public std::runtime_error
{

View File

@ -30,7 +30,7 @@
namespace xlnt {
/// <summary>
/// Error when a references number format is not in the stylesheet.
/// Error when a referenced number format is not in the stylesheet.
/// </summary>
class XLNT_CLASS missing_number_format : public std::runtime_error
{

View File

@ -30,7 +30,7 @@
namespace xlnt {
/// <summary>
/// Error for badly formatted named ranges.
/// Error for incorrectly formatted named ranges.
/// </summary>
class XLNT_CLASS named_range_exception : public std::runtime_error
{

View File

@ -30,7 +30,7 @@
namespace xlnt {
/// <summary>
/// Security information about the document.
/// Security information about the OOXML document.
/// </summary>
class XLNT_CLASS document_security
{

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// A reference to an external workbook for use in formulae.
/// </summary>
class XLNT_CLASS external_book
{
};

View File

@ -33,8 +33,13 @@ namespace xlnt {
class range_reference;
class worksheet;
//TODO: why is this not in a class?
std::vector<std::pair<std::string, std::string>> XLNT_FUNCTION split_named_range(const std::string &named_range_string);
/// <summary>
/// A 2D range of cells in a worksheet that is referred to by name.
/// ws->get_range("A1:B2") could be replaced by ws->get_range("range1")
/// </summary>
class XLNT_CLASS named_range
{
public:

View File

@ -26,6 +26,10 @@
namespace xlnt {
/// <summary>
/// A theme is a combination of fonts, colors, and effects.
/// This isn't really supported yet.
/// </summary>
class XLNT_CLASS theme
{
};

View File

@ -35,78 +35,33 @@ namespace xlnt {
class cell;
class range_reference;
/// <summary>
/// A cell vector is a linear (1D) range of cells, either vertical or horizontal
/// depending on the major order specified in the constructor.
/// </summary>
class XLNT_CLASS cell_vector
{
public:
template <bool is_const = true>
class XLNT_CLASS common_iterator : public std::iterator<std::bidirectional_iterator_tag, cell>
class XLNT_CLASS iterator : public std::iterator<std::bidirectional_iterator_tag, cell>
{
public:
common_iterator(worksheet ws, const cell_reference &start_cell, major_order order = major_order::row)
: ws_(ws), current_cell_(start_cell), range_(start_cell.to_range()), order_(order)
{
}
iterator(worksheet ws, const cell_reference &start_cell, major_order order = major_order::row);
common_iterator(const common_iterator<false> &other)
{
*this = other;
}
iterator(const iterator &other);
cell operator*();
bool operator==(const common_iterator &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool operator==(const iterator &other) const;
bool operator!=(const common_iterator &other) const
{
return !(*this == other);
}
bool operator!=(const iterator &other) const;
common_iterator &operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
iterator &operator--();
iterator operator--(int);
return *this;
}
iterator &operator++();
common_iterator operator--(int)
{
iterator old = *this;
--*this;
return old;
}
common_iterator &operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
return *this;
}
common_iterator operator++(int)
{
iterator old = *this;
++*this;
return old;
}
friend class common_iterator<true>;
iterator operator++(int);
private:
worksheet ws_;
@ -114,9 +69,34 @@ class XLNT_CLASS cell_vector
range_reference range_;
major_order order_;
};
class XLNT_CLASS const_iterator : public std::iterator<std::bidirectional_iterator_tag, const cell>
{
public:
const_iterator(worksheet ws, const cell_reference &start_cell, major_order order = major_order::row);
using iterator = common_iterator<false>;
using const_iterator = common_iterator<true>;
const_iterator(const const_iterator &other);
const cell operator*();
bool operator==(const const_iterator &other) const;
bool operator!=(const const_iterator &other) const;
const_iterator &operator--();
const_iterator operator--(int);
const_iterator &operator++();
const_iterator operator++(int);
private:
worksheet ws_;
cell_reference current_cell_;
range_reference range_;
major_order order_;
};
cell_vector(worksheet ws, const range_reference &ref, major_order order = major_order::row);

View File

@ -27,6 +27,10 @@
namespace xlnt {
/// <summary>
/// Properties applied to a column in a worksheet.
/// Columns can have a size and a style.
/// </summary>
class XLNT_CLASS column_properties
{
public:

View File

@ -14,30 +14,16 @@ class XLNT_CLASS footer
{
public:
footer();
void set_text(const std::string &text)
{
default_ = false;
text_ = text;
}
void set_font_name(const std::string &font_name)
{
default_ = false;
font_name_ = font_name;
}
void set_font_size(std::size_t font_size)
{
default_ = false;
font_size_ = font_size;
}
void set_font_color(const std::string &font_color)
{
default_ = false;
font_color_ = font_color;
}
bool is_default() const
{
return default_;
}
void set_text(const std::string &text);
void set_font_name(const std::string &font_name);
void set_font_size(std::size_t font_size);
void set_font_color(const std::string &font_color);
bool is_default() const;
private:
bool default_;

View File

@ -14,30 +14,16 @@ class XLNT_CLASS header
{
public:
header();
void set_text(const std::string &text)
{
default_ = false;
text_ = text;
}
void set_font_name(const std::string &font_name)
{
default_ = false;
font_name_ = font_name;
}
void set_font_size(std::size_t font_size)
{
default_ = false;
font_size_ = font_size;
}
void set_font_color(const std::string &font_color)
{
default_ = false;
font_color_ = font_color;
}
bool is_default() const
{
return default_;
}
void set_text(const std::string &text);
void set_font_name(const std::string &font_name);
void set_font_size(std::size_t font_size);
void set_font_color(const std::string &font_color);
bool is_default() const;
private:
bool default_;

View File

@ -10,7 +10,7 @@
namespace xlnt {
/// <summary>
/// Worksheet header and footer
/// Worksheet header and footer for all six possible positions.
/// </summary>
class XLNT_CLASS header_footer
{

View File

@ -26,6 +26,9 @@
namespace xlnt {
/// <summary>
/// Defines whether iterating a range returns columns or rows sequentially.
/// </summary>
enum class XLNT_CLASS major_order
{
column,

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// The orientation of the worksheet when it is printed.
/// </summary>
enum class XLNT_CLASS orientation
{
portrait,

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// The types of page breaks.
/// </summary>
enum class XLNT_CLASS page_break
{
none = 0,

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// Describes the margins around a worksheet for printing.
/// </summary>
class XLNT_CLASS page_margins
{
public:

View File

@ -31,6 +31,9 @@
namespace xlnt {
/// <summary>
/// Describes how a worksheet will be converted into a page during printing.
/// </summary>
struct XLNT_CLASS page_setup
{
public:

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// A fixed portion of a worksheet.
/// </summary>
class XLNT_CLASS pane
{
};

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// The possible paper sizes for printing.
/// </summary>
enum class XLNT_CLASS paper_size
{
letter = 1,

View File

@ -30,95 +30,22 @@
#include <xlnt/xlnt_config.hpp>
#include <xlnt/worksheet/cell_vector.hpp>
#include <xlnt/worksheet/major_order.hpp>
#include <xlnt/worksheet/range_iterator_2d.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp>
namespace xlnt {
/// <summary>
/// A range is a 2D collection of cells with defined extens that can be iterated upon.
/// </summary>
class XLNT_CLASS range
{
public:
template <bool is_const = true>
class XLNT_CLASS common_iterator : public std::iterator<std::bidirectional_iterator_tag, cell>
{
public:
common_iterator(worksheet ws, const range_reference &start_cell, major_order order = major_order::row)
: ws_(ws), current_cell_(start_cell.get_top_left()), range_(start_cell), order_(order)
{
}
common_iterator(const common_iterator<false> &other)
{
*this = other;
}
cell_vector operator*();
bool operator==(const common_iterator &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool operator!=(const common_iterator &other) const
{
return !(*this == other);
}
common_iterator &operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
return *this;
}
common_iterator operator--(int)
{
iterator old = *this;
--*this;
return old;
}
common_iterator &operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
return *this;
}
common_iterator operator++(int)
{
iterator old = *this;
++*this;
return old;
}
friend class common_iterator<true>;
private:
worksheet ws_;
cell_reference current_cell_;
range_reference range_;
major_order order_;
};
using iterator = common_iterator<false>;
using const_iterator = common_iterator<true>;
range(worksheet ws, const range_reference &reference, major_order order = major_order::row);
using iterator = range_iterator_2d;
using const_iterator = const_range_iterator_2d;
range(worksheet ws, const range_reference &reference, major_order order = major_order::row, bool skip_null = false);
~range();
@ -128,10 +55,7 @@ class XLNT_CLASS range
bool operator==(const range &comparand) const;
bool operator!=(const range &comparand) const
{
return !(*this == comparand);
}
bool operator!=(const range &comparand) const;
cell_vector get_vector(std::size_t vector_index);
@ -150,14 +74,8 @@ class XLNT_CLASS range
iterator begin();
iterator end();
const_iterator begin() const
{
return cbegin();
}
const_iterator end() const
{
return cend();
}
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
@ -166,6 +84,7 @@ class XLNT_CLASS range
worksheet ws_;
range_reference ref_;
major_order order_;
bool skip_null_;
};
} // namespace xlnt

View File

@ -0,0 +1,80 @@
#pragma once
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/worksheet/major_order.hpp>
#include <xlnt/worksheet/range_reference.hpp>
namespace xlnt {
class cell_vector;
class worksheet;
namespace detail { struct worksheet_impl; }
/// <summary>
/// An iterator used by worksheet and range for traversing
/// a 2D grid of cells by row/column then across that row/column.
/// </summary>
class XLNT_CLASS range_iterator_2d : public std::iterator<std::bidirectional_iterator_tag, cell_vector>
{
public:
range_iterator_2d(worksheet &ws, const range_reference &start_cell, major_order order = major_order::row);
range_iterator_2d(const range_iterator_2d &other);
cell_vector operator*();
bool operator==(const range_iterator_2d &other) const;
bool operator!=(const range_iterator_2d &other) const;
range_iterator_2d &operator--();
range_iterator_2d operator--(int);
range_iterator_2d &operator++();
range_iterator_2d operator++(int);
private:
detail::worksheet_impl *ws_;
cell_reference current_cell_;
range_reference range_;
major_order order_;
};
/// <summary>
/// A const version of range_iterator_2d which does not allow modification
/// to the dereferenced cell_vector.
/// </summary>
class XLNT_CLASS const_range_iterator_2d : public std::iterator<std::bidirectional_iterator_tag, const cell_vector>
{
public:
const_range_iterator_2d(const worksheet &ws, const range_reference &start_cell, major_order order = major_order::row);
const_range_iterator_2d(const const_range_iterator_2d &other);
const cell_vector operator*();
bool operator==(const const_range_iterator_2d &other) const;
bool operator!=(const const_range_iterator_2d &other) const;
const_range_iterator_2d &operator--();
const_range_iterator_2d operator--(int);
const_range_iterator_2d &operator++();
const_range_iterator_2d operator++(int);
private:
detail::worksheet_impl *ws_;
cell_reference current_cell_;
range_reference range_;
major_order order_;
};
} // namespace xlnt

View File

@ -27,6 +27,10 @@
namespace xlnt {
/// <summary>
/// A range_reference describes a rectangular area of a worksheet with positive
/// width and height defined by a top-left and bottom-right corner.
/// </summary>
class XLNT_CLASS range_reference
{
public:
@ -48,69 +52,43 @@ class XLNT_CLASS range_reference
std::size_t get_height() const;
cell_reference get_top_left() const
{
return top_left_;
}
cell_reference get_bottom_right() const
{
return bottom_right_;
}
cell_reference &get_top_left()
{
return top_left_;
}
cell_reference &get_bottom_right()
{
return bottom_right_;
}
cell_reference get_top_left() const;
cell_reference get_bottom_right() const;
cell_reference &get_top_left();
cell_reference &get_bottom_right();
range_reference make_offset(int column_offset, int row_offset) const;
std::string to_string() const;
bool operator==(const range_reference &comparand) const;
bool operator==(const std::string &reference_string) const
{
return *this == range_reference(reference_string);
}
bool operator==(const char *reference_string) const
{
return *this == std::string(reference_string);
}
bool operator==(const std::string &reference_string) const;
bool operator==(const char *reference_string) const;
bool operator!=(const range_reference &comparand) const;
bool operator!=(const std::string &reference_string) const
{
return *this != range_reference(reference_string);
}
bool operator!=(const char *reference_string) const
{
return *this != std::string(reference_string);
}
bool operator!=(const std::string &reference_string) const;
bool operator!=(const char *reference_string) const;
XLNT_FUNCTION friend bool operator==(const std::string &reference_string, const range_reference &ref);
XLNT_FUNCTION friend bool operator==(const char *reference_string, const range_reference &ref);
XLNT_FUNCTION friend bool operator!=(const std::string &reference_string, const range_reference &ref);
XLNT_FUNCTION friend bool operator!=(const char *reference_string, const range_reference &ref);
private:
cell_reference top_left_;
cell_reference bottom_right_;
};
inline bool XLNT_FUNCTION operator==(const std::string &reference_string, const range_reference &ref)
{
return ref == reference_string;
}
inline bool XLNT_FUNCTION operator==(const char *reference_string, const range_reference &ref)
{
return ref == reference_string;
}
inline bool XLNT_FUNCTION operator!=(const std::string &reference_string, const range_reference &ref)
{
return ref != reference_string;
}
inline bool XLNT_FUNCTION operator!=(const char *reference_string, const range_reference &ref)
{
return ref != reference_string;
}
} // namespace xlnt

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// The properties of a row in a worksheet.
/// </summary>
class XLNT_CLASS row_properties
{
public:

View File

@ -26,6 +26,9 @@
namespace xlnt {
/// <summary>
/// The selected area of a worksheet.
/// </summary>
class XLNT_CLASS selection
{
};

View File

@ -29,16 +29,16 @@
namespace xlnt {
/// <summary>
/// Protection applied to a particular worksheet to prevent it from being modified.
/// </summary>
class XLNT_CLASS sheet_protection
{
public:
static std::string hash_password(const std::string &password);
void set_password(const std::string &password);
std::string get_hashed_password() const
{
return hashed_password_;
}
std::string get_hashed_password() const;
private:
std::string hashed_password_;

View File

@ -27,6 +27,10 @@
namespace xlnt {
/// <summary>
/// Defines how a worksheet appears in the workbook.
/// A workbook must have at least one sheet which is visible at all times.
/// </summary>
enum class XLNT_CLASS sheet_state
{
visible,

View File

@ -27,6 +27,10 @@
namespace xlnt {
/// <summary>
/// Describes a view of a worksheet.
/// Worksheets can have multiple views which show the data differently.
/// </summary>
class XLNT_CLASS sheet_view
{
};

View File

@ -23,23 +23,24 @@
// @author: see AUTHORS file
#pragma once
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
#include <xlnt/xlnt_config.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/packaging/relationship.hpp>
#include <xlnt/worksheet/header_footer.hpp>
#include <xlnt/worksheet/page_margins.hpp>
#include <xlnt/worksheet/page_setup.hpp>
#include <xlnt/worksheet/range_iterator_2d.hpp>
namespace xlnt {
class cell;
class cell_reference;
class cell_vector;
class column_properties;
class comment;
class range;
@ -53,11 +54,15 @@ struct date;
namespace detail { struct worksheet_impl; }
/// <summary>
/// A worksheet is a 2D array of cells.
/// A worksheet is a 2D array of cells starting with cell A1 in the top-left corner
/// and extending indefinitely down and right as needed.
/// </summary>
class XLNT_CLASS worksheet
{
public:
public:
using iterator = range_iterator_2d;
using const_iterator = const_range_iterator_2d;
worksheet();
worksheet(const worksheet &rhs);
worksheet(workbook &parent_workbook, const std::string &title = std::string());
@ -92,7 +97,6 @@ class XLNT_CLASS worksheet
range rows(int row_offset, int column_offset) const;
range rows(const std::string &range_string, int row_offset, int column_offset) const;
range columns() const;
std::list<cell> get_cell_collection();
// properties
column_properties &get_column_properties(column_t column);
@ -198,9 +202,23 @@ class XLNT_CLASS worksheet
void set_sheet_state(sheet_state state);
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
const_iterator cbegin() const;
const_iterator cend() const;
range iter_cells(bool skip_null);
private:
friend class workbook;
friend class cell;
friend class range_iterator_2d;
friend class const_range_iterator_2d;
worksheet(detail::worksheet_impl *d);
detail::worksheet_impl *d_;
};

View File

@ -27,6 +27,9 @@
namespace xlnt {
/// <summary>
/// ?
/// </summary>
class XLNT_CLASS worksheet_properties
{
};

View File

@ -26,7 +26,7 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/cell/comment.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/packaging/relationship.hpp>

View File

@ -21,767 +21,6 @@
#include <detail/cell_impl.hpp>
#include <detail/comment_impl.hpp>
namespace {
enum class condition_type
{
less_than,
less_or_equal,
equal,
greater_than,
greater_or_equal,
invalid
};
struct section
{
bool has_value = false;
std::string value;
bool has_color = false;
std::string color;
bool has_condition = false;
condition_type condition = condition_type::invalid;
std::string condition_value;
bool has_locale = false;
std::string locale;
section &operator=(const section &other)
{
has_value = other.has_value;
value = other.value;
has_color = other.has_color;
color = other.color;
has_condition = other.has_condition;
condition = other.condition;
condition_value = other.condition_value;
has_locale = other.has_locale;
locale = other.locale;
return *this;
}
};
struct format_sections
{
section first;
section second;
section third;
section fourth;
};
// copied from named_range.cpp, keep in sync
/// <summary>
/// Return a vector containing string split at each delim.
/// </summary>
/// <remark>
/// This should maybe be in a utility header so it can be used elsewhere.
/// </remarks>
std::vector<std::string> split_string(const std::string &string, char delim)
{
std::vector<std::string> split;
std::string::size_type previous_index = 0;
auto separator_index = string.find(delim);
while (separator_index != std::string::npos)
{
auto part = string.substr(previous_index, separator_index - previous_index);
split.push_back(part);
previous_index = separator_index + 1;
separator_index = string.find(delim, previous_index);
}
split.push_back(string.substr(previous_index));
return split;
}
std::vector<std::string> split_string_any(const std::string &string, const std::string &delims)
{
std::vector<std::string> split;
std::string::size_type previous_index = 0;
auto separator_index = string.find_first_of(delims);
while (separator_index != std::string::npos)
{
auto part = string.substr(previous_index, separator_index - previous_index);
if (!part.empty())
{
split.push_back(part);
}
previous_index = separator_index + 1;
separator_index = string.find_first_of(delims, previous_index);
}
split.push_back(string.substr(previous_index));
return split;
}
bool is_date_format(const std::string &format_string)
{
auto not_in = format_string.find_first_not_of("/-:, mMyYdDhHsS");
return not_in == std::string::npos;
}
bool is_valid_color(const std::string &color)
{
static const std::vector<std::string> *colors =
new std::vector<std::string>(
{
"Black",
"Green"
"White",
"Blue",
"Magenta",
"Yellow",
"Cyan",
"Red"
});
auto compare_color = [&](const std::string &other) {
if (color.size() != other.size()) return false;
for (std::size_t i = 0; i < color.size(); i++)
{
if (std::toupper(color[i]) != std::toupper(other[i]))
{
return false;
}
}
return true;
};
return std::find_if(colors->begin(), colors->end(), compare_color) != colors->end();
}
bool parse_condition(const std::string &string, section &s)
{
s.has_condition = false;
s.condition = condition_type::invalid;
s.condition_value.clear();
if (string[0] == '<')
{
s.has_condition = true;
if (string[1] == '=')
{
s.condition = condition_type::less_or_equal;
s.condition_value = string.substr(2);
}
else
{
s.condition = condition_type::less_than;
s.condition_value = string.substr(1);
}
}
if (string[0] == '>')
{
s.has_condition = true;
if (string[1] == '=')
{
s.condition = condition_type::greater_or_equal;
s.condition_value = string.substr(2);
}
else
{
s.condition = condition_type::greater_than;
s.condition_value = string.substr(1);
}
}
else if (string[0] == '=')
{
s.has_condition = true;
s.condition = condition_type::equal;
s.condition_value = string.substr(1);
}
return s.has_condition;
}
bool is_hex(char c)
{
if (c >= 'A' || c <= 'F') return true;
if (c >= '0' || c <= '9') return true;
return false;
}
const std::unordered_map<int, std::string> known_locales()
{
const std::unordered_map<int, std::string> *all =
new std::unordered_map<int, std::string>(
{
{ 0x401, "Arabic - Saudi Arabia" },
{ 0x402, "Bulgarian" },
{ 0x403, "Catalan" },
{ 0x404, "Chinese - Taiwan" },
{ 0x405, "Czech" },
{ 0x406, "Danish" },
{ 0x407, "German - Germany" },
{ 0x408, "Greek" },
{ 0x409, "English - United States" },
{ 0x410, "Italian - Italy" },
{ 0x411, "Japanese" },
{ 0x412, "Korean" },
{ 0x413, "Dutch - Netherlands" },
{ 0x414, "Norwegian - Bokml" },
{ 0x415, "Polish" },
{ 0x416, "Portuguese - Brazil" },
{ 0x417, "Raeto-Romance" },
{ 0x418, "Romanian - Romania" },
{ 0x419, "Russian" },
{ 0x420, "Urdu" },
{ 0x421, "Indonesian" },
{ 0x422, "Ukrainian" },
{ 0x423, "Belarusian" },
{ 0x424, "Slovenian" },
{ 0x425, "Estonian" },
{ 0x426, "Latvian" },
{ 0x427, "Lithuanian" },
{ 0x428, "Tajik" },
{ 0x429, "Farsi - Persian" },
{ 0x430, "Sesotho (Sutu)" },
{ 0x431, "Tsonga" },
{ 0x432, "Setsuana" },
{ 0x433, "Venda" },
{ 0x434, "Xhosa" },
{ 0x435, "Zulu" },
{ 0x436, "Afrikaans" },
{ 0x437, "Georgian" },
{ 0x438, "Faroese" },
{ 0x439, "Hindi" },
{ 0x440, "Kyrgyz - Cyrillic" },
{ 0x441, "Swahili" },
{ 0x442, "Turkmen" },
{ 0x443, "Uzbek - Latin" },
{ 0x444, "Tatar" },
{ 0x445, "Bengali - India" },
{ 0x446, "Punjabi" },
{ 0x447, "Gujarati" },
{ 0x448, "Oriya" },
{ 0x449, "Tamil" },
{ 0x450, "Mongolian" },
{ 0x451, "Tibetan" },
{ 0x452, "Welsh" },
{ 0x453, "Khmer" },
{ 0x454, "Lao" },
{ 0x455, "Burmese" },
{ 0x456, "Galician" },
{ 0x457, "Konkani" },
{ 0x458, "Manipuri" },
{ 0x459, "Sindhi" },
{ 0x460, "Kashmiri" },
{ 0x461, "Nepali" },
{ 0x462, "Frisian - Netherlands" },
{ 0x464, "Filipino" },
{ 0x465, "Divehi; Dhivehi; Maldivian" },
{ 0x466, "Edo" },
{ 0x470, "Igbo - Nigeria" },
{ 0x474, "Guarani - Paraguay" },
{ 0x476, "Latin" },
{ 0x477, "Somali" },
{ 0x481, "Maori" },
{ 0x801, "Arabic - Iraq" },
{ 0x804, "Chinese - China" },
{ 0x807, "German - Switzerland" },
{ 0x809, "English - Great Britain" },
{ 0x810, "Italian - Switzerland" },
{ 0x813, "Dutch - Belgium" },
{ 0x814, "Norwegian - Nynorsk" },
{ 0x816, "Portuguese - Portugal" },
{ 0x818, "Romanian - Moldova" },
{ 0x819, "Russian - Moldova" },
{ 0x843, "Uzbek - Cyrillic" },
{ 0x845, "Bengali - Bangladesh" },
{ 0x850, "Mongolian" },
{ 0x1001, "Arabic - Libya" },
{ 0x1004, "Chinese - Singapore" },
{ 0x1007, "German - Luxembourg" },
{ 0x1009, "English - Canada" },
{ 0x1401, "Arabic - Algeria" },
{ 0x1404, "Chinese - Macau SAR" },
{ 0x1407, "German - Liechtenstein" },
{ 0x1409, "English - New Zealand" },
{ 0x1801, "Arabic - Morocco" },
{ 0x1809, "English - Ireland" },
{ 0x2001, "Arabic - Oman" },
{ 0x2009, "English - Jamaica" },
{ 0x2401, "Arabic - Yemen" },
{ 0x2409, "English - Caribbean" },
{ 0x2801, "Arabic - Syria" },
{ 0x2809, "English - Belize" },
{ 0x3001, "Arabic - Lebanon" },
{ 0x3009, "English - Zimbabwe" },
{ 0x3401, "Arabic - Kuwait" },
{ 0x3409, "English - Phillippines" },
{ 0x3801, "Arabic - United Arab Emirates" },
{ 0x4001, "Arabic - Qatar" }
});
return *all;
}
bool is_valid_locale(const std::string &locale_string)
{
std::string country = locale_string.substr(locale_string.find('-') + 1);
if (country.empty())
{
return false;
}
for (auto c : country)
{
if (!is_hex(static_cast<char>(std::toupper(c))))
{
return false;
}
}
auto index = std::stoi(country, 0, 16);
auto known_locales_ = known_locales();
if (known_locales_.find(index) == known_locales_.end())
{
return false;
}
std::string beginning = locale_string.substr(0, locale_string.find('-'));
if (beginning.empty() || beginning[0] != '$')
{
return false;
}
if (beginning.size() == 1)
{
return true;
}
beginning = beginning.substr(1);
return true;
}
section parse_section(const std::string &section_string)
{
section s;
std::string format_part;
std::string bracket_part;
std::vector<std::string> bracket_parts;
bool in_quotes = false;
bool in_brackets = false;
const std::vector<std::string> bracket_times = { "h", "hh", "m", "mm", "s", "ss" };
for (std::size_t i = 0; i < section_string.size(); i++)
{
if (!in_quotes && section_string[i] == '"')
{
format_part.push_back(section_string[i]);
in_quotes = true;
}
else if (in_quotes && section_string[i] == '"')
{
format_part.push_back(section_string[i]);
if (i < section_string.size() - 1 && section_string[i + 1] != '"')
{
in_quotes = false;
}
}
else if (!in_brackets && section_string[i] == '[')
{
in_brackets = true;
for (auto bracket_time : bracket_times)
{
if (i < section_string.size() - bracket_time.size() &&
section_string.substr(i + 1, bracket_time.size()) == bracket_time)
{
in_brackets = false;
break;
}
}
}
else if (in_brackets)
{
if (section_string[i] == ']')
{
in_brackets = false;
if (is_valid_color(bracket_part))
{
if (s.color.empty())
{
s.color = bracket_part;
s.has_color = true;
}
else
{
throw std::runtime_error("two colors");
}
}
else if (is_valid_locale(bracket_part))
{
if (s.locale.empty())
{
s.locale = bracket_part;
s.has_locale = true;
}
else
{
throw std::runtime_error("two locales");
}
}
else if (s.has_condition || !parse_condition(bracket_part, s))
{
throw std::runtime_error("invalid bracket format");
}
bracket_part.clear();
}
else
{
bracket_part.push_back(section_string[i]);
}
}
else
{
format_part.push_back(section_string[i]);
}
}
s.value = format_part;
s.has_value = true;
return s;
}
format_sections parse_format_sections(const std::string &combined)
{
format_sections result = {};
auto split = split_string(combined, ';');
if (split.empty())
{
throw std::runtime_error("empty string");
}
result.first = parse_section(split[0]);
if (!result.first.has_condition)
{
result.second = result.first;
result.third = result.first;
}
if (split.size() > 1)
{
result.second = parse_section(split[1]);
}
if (split.size() > 2)
{
if (result.first.has_condition && !result.second.has_condition)
{
throw std::runtime_error("first two sections should have conditions");
}
result.third = parse_section(split[2]);
if (result.third.has_condition)
{
throw std::runtime_error("third section shouldn't have a condition");
}
}
if (split.size() > 3)
{
if (result.first.has_condition)
{
throw std::runtime_error("too many parts");
}
result.fourth = parse_section(split[3]);
}
if (split.size() > 4)
{
throw std::runtime_error("too many parts");
}
return result;
}
std::string format_section(long double number, const section &format, xlnt::calendar base_date)
{
const std::string unquoted = "$+(:^'{<=-/)!&~}> ";
std::string format_temp = format.value;
std::string result;
if (is_date_format(format.value))
{
const std::string date_unquoted = ",-/: ";
const std::vector<std::string> dates = { "m", "mm", "mmm", "mmmmm", "mmmmmm", "d", "dd", "ddd", "dddd", "yy",
"yyyy", "h", "[h]", "hh", "m", "[m]", "mm", "s", "[s]", "ss", "AM/PM",
"am/pm", "A/P", "a/p" };
const std::vector<std::string> MonthNames = { "January", "February", "March",
"April", "May", "June", "July", "August", "September", "October", "November", "December" };
auto split = split_string_any(format.value, date_unquoted);
std::string::size_type index = 0, prev = 0;
auto d = xlnt::datetime::from_number(number, base_date);
bool processed_month = false;
auto lower_string = [](const std::string &s) {
std::string lower;
lower.resize(s.size());
for (std::size_t i = 0; i < s.size(); i++)
lower[i] = static_cast<char>(std::tolower(s[i]));
return lower;
};
for (auto part : split)
{
while (format.value.substr(index, part.size()) != part)
{
index++;
}
auto between = format.value.substr(prev, index - prev);
result.append(between);
part = lower_string(part);
if (part == "m" && !processed_month)
{
result.append(std::to_string(d.month));
processed_month = true;
}
else if (part == "mm" && !processed_month)
{
if (d.month < 10)
{
result.append("0");
}
result.append(std::to_string(d.month));
processed_month = true;
}
else if (part == "mmm" && !processed_month)
{
result.append(MonthNames.at(static_cast<std::size_t>(d.month - 1)).substr(0, 3));
processed_month = true;
}
else if (part == "mmmm" && !processed_month)
{
result.append(MonthNames.at(static_cast<std::size_t>(d.month - 1)));
processed_month = true;
}
else if (part == "d")
{
result.append(std::to_string(d.day));
}
else if (part == "dd")
{
if (d.day < 10)
{
result.append("0");
}
result.append(std::to_string(d.day));
}
else if (part == "yyyy")
{
result.append(std::to_string(d.year));
}
else if (part == "h")
{
result.append(std::to_string(d.hour));
processed_month = true;
}
else if (part == "hh")
{
if (d.hour < 10)
{
result.append("0");
}
result.append(std::to_string(d.hour));
processed_month = true;
}
else if (part == "m")
{
result.append(std::to_string(d.minute));
}
else if (part == "mm")
{
if (d.minute < 10)
{
result.append("0");
}
result.append(std::to_string(d.minute));
}
else if (part == "s")
{
result.append(std::to_string(d.second));
}
else if (part == "ss")
{
if (d.second < 10)
{
result.append("0");
}
result.append(std::to_string(d.second));
}
else if (part == "am/pm" || part == "a/p")
{
if (d.hour < 12)
{
result.append("AM");
}
else
{
result.append("PM");
}
}
index += part.size();
prev = index;
}
if (index < format.value.size())
{
result.append(format.value.substr(index));
}
}
else if (format.value == "General" || format.value == "0")
{
if (number == static_cast<long long int>(number))
{
result = std::to_string(static_cast<long long int>(number));
}
else
{
result = std::to_string(number);
}
}
else if (format.value.substr(0, 8) == "#,##0.00" || format.value.substr(0, 9) == "-#,##0.00")
{
if (format.value[0] == '-')
{
result = "-";
}
if (format.has_locale && format.locale == "$$-1009")
{
result += "CA$";
}
else if (format.has_locale && format.locale == "$€-407")
{
result += "";
}
else
{
result += "$";
}
result += std::to_string(number < 0 ? -number : number);
auto decimal_pos = result.find('.');
if (decimal_pos != std::string::npos)
{
result[decimal_pos] = ',';
decimal_pos += 3;
while (decimal_pos < result.size())
{
result.pop_back();
}
}
}
return result;
}
std::string format_section(const std::string &text, const section &format)
{
auto arobase_index = format.value.find('@');
std::string first_part, middle_part, last_part;
if (arobase_index != std::string::npos)
{
first_part = format.value.substr(0, arobase_index);
middle_part = text;
last_part = format.value.substr(arobase_index + 1);
}
else
{
first_part = format.value;
}
auto unquote = [](std::string &s) {
if (!s.empty())
{
if (s.front() != '"' || s.back() != '"') return false;
s = s.substr(0, s.size() - 2);
}
return true;
};
if (!unquote(first_part) || !unquote(last_part))
{
throw std::runtime_error(std::string("additional text must be enclosed in quotes: ") + format.value);
}
return first_part + middle_part + last_part;
}
std::string format_number(long double number, const std::string &format, xlnt::calendar base_date)
{
auto sections = parse_format_sections(format);
if (number > 0)
{
return format_section(number, sections.first, base_date);
}
else if (number < 0)
{
return format_section(number, sections.second, base_date);
}
// number == 0
return format_section(number, sections.third, base_date);
}
std::string format_text(const std::string &text, const std::string &format)
{
if (format == "General") return text;
auto sections = parse_format_sections(format);
return format_section(text, sections.fourth);
}
}
namespace xlnt {
const std::unordered_map<std::string, int> &cell::error_codes()
@ -1012,25 +251,7 @@ bool cell::is_merged() const
bool cell::is_date() const
{
if (get_data_type() == type::numeric)
{
auto number_format = get_number_format().get_format_string();
if (number_format != "General")
{
try
{
auto sections = parse_format_sections(number_format);
return is_date_format(sections.first.value);
}
catch (std::exception)
{
return false;
}
}
}
return false;
return get_data_type() == type::numeric && get_number_format().is_date_format();
}
cell_reference cell::get_reference() const
@ -1448,11 +669,11 @@ std::string cell::to_string() const
case cell::type::null:
return "";
case cell::type::numeric:
return format_number(get_value<long double>(), nf.get_format_string(), get_base_date());
return get_number_format().format(get_value<long double>(), get_base_date());
case cell::type::string:
case cell::type::formula:
case cell::type::error:
return format_text(get_value<std::string>(), nf.get_format_string());
return get_number_format().format(get_value<std::string>());
case cell::type::boolean:
return get_value<long double>() == 0 ? "FALSE" : "TRUE";
default:

View File

@ -1,6 +1,6 @@
#include <locale>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/utils/exceptions.hpp>
#include <detail/constants.hpp>

View File

@ -4,7 +4,7 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/comment.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/utils/exceptions.hpp>
#include <xlnt/utils/time.hpp>
#include <xlnt/packaging/relationship.hpp>

View File

@ -3,7 +3,7 @@
#include <string>
#include <unordered_map>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
namespace xlnt {

View File

@ -16,4 +16,119 @@ relationship::relationship()
{
}
relationship::type relationship::type_from_string(const std::string &type_string)
{
if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties")
{
return type::extended_properties;
}
else if (type_string == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties")
{
return type::core_properties;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument")
{
return type::office_document;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet")
{
return type::worksheet;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings")
{
return type::shared_strings;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles")
{
return type::styles;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")
{
return type::theme;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink")
{
return type::hyperlink;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet")
{
return type::chartsheet;
}
else if (type_string == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml")
{
return type::custom_xml;
}
return type::invalid;
}
std::string relationship::type_to_string(type t)
{
switch (t)
{
case type::extended_properties:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
case type::core_properties:
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
case type::office_document:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
case type::worksheet:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
case type::shared_strings:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
case type::styles:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
case type::theme:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
case type::hyperlink:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
case type::chartsheet:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
case type::custom_xml:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
default:
return "??";
}
}
relationship::relationship(const std::string &t, const std::string &r_id, const std::string &target_uri)
: relationship(type_from_string(t), r_id, target_uri)
{
}
std::string relationship::get_id() const
{
return id_;
}
std::string relationship::get_source_uri() const
{
return source_uri_;
}
target_mode relationship::get_target_mode() const
{
return target_mode_;
}
std::string relationship::get_target_uri() const
{
return target_uri_;
}
relationship::type relationship::get_type() const
{
return type_;
}
std::string relationship::get_type_string() const
{
return type_to_string(type_);
}
bool relationship::operator==(const relationship &rhs) const
{
return type_ == rhs.type_ && id_ == rhs.id_ && source_uri_ == rhs.source_uri_ &&
target_uri_ == rhs.target_uri_ && target_mode_ == rhs.target_mode_;
}
} // namespace xlnt

View File

@ -160,19 +160,19 @@ alignment style_serializer::read_alignment(const xml_node &alignment_node)
if (vertical == "bottom")
{
align.set_vertical(alignment::vertical_alignment::bottom);
align.set_vertical(vertical_alignment::bottom);
}
else if (vertical == "center")
{
align.set_vertical(alignment::vertical_alignment::center);
align.set_vertical(vertical_alignment::center);
}
else if (vertical == "justify")
{
align.set_vertical(alignment::vertical_alignment::justify);
align.set_vertical(vertical_alignment::justify);
}
else if (vertical == "top")
{
align.set_vertical(alignment::vertical_alignment::top);
align.set_vertical(vertical_alignment::top);
}
else
{
@ -188,27 +188,27 @@ alignment style_serializer::read_alignment(const xml_node &alignment_node)
if (horizontal == "left")
{
align.set_horizontal(alignment::horizontal_alignment::left);
align.set_horizontal(horizontal_alignment::left);
}
else if (horizontal == "center")
{
align.set_horizontal(alignment::horizontal_alignment::center);
align.set_horizontal(horizontal_alignment::center);
}
else if (horizontal == "center-continuous")
{
align.set_horizontal(alignment::horizontal_alignment::center_continuous);
align.set_horizontal(horizontal_alignment::center_continuous);
}
else if (horizontal == "right")
{
align.set_horizontal(alignment::horizontal_alignment::right);
align.set_horizontal(horizontal_alignment::right);
}
else if (horizontal == "justify")
{
align.set_horizontal(alignment::horizontal_alignment::justify);
align.set_horizontal(horizontal_alignment::justify);
}
else if (horizontal == "general")
{
align.set_horizontal(alignment::horizontal_alignment::general);
align.set_horizontal(horizontal_alignment::general);
}
else
{
@ -885,16 +885,16 @@ xml_document style_serializer::write_stylesheet() const
{
switch (style.alignment_.get_vertical())
{
case alignment::vertical_alignment::bottom:
case vertical_alignment::bottom:
alignment_node.add_attribute("vertical", "bottom");
break;
case alignment::vertical_alignment::center:
case vertical_alignment::center:
alignment_node.add_attribute("vertical", "center");
break;
case alignment::vertical_alignment::justify:
case vertical_alignment::justify:
alignment_node.add_attribute("vertical", "justify");
break;
case alignment::vertical_alignment::top:
case vertical_alignment::top:
alignment_node.add_attribute("vertical", "top");
break;
default:
@ -906,22 +906,22 @@ xml_document style_serializer::write_stylesheet() const
{
switch (style.alignment_.get_horizontal())
{
case alignment::horizontal_alignment::center:
case horizontal_alignment::center:
alignment_node.add_attribute("horizontal", "center");
break;
case alignment::horizontal_alignment::center_continuous:
case horizontal_alignment::center_continuous:
alignment_node.add_attribute("horizontal", "center_continuous");
break;
case alignment::horizontal_alignment::general:
case horizontal_alignment::general:
alignment_node.add_attribute("horizontal", "general");
break;
case alignment::horizontal_alignment::justify:
case horizontal_alignment::justify:
alignment_node.add_attribute("horizontal", "justify");
break;
case alignment::horizontal_alignment::left:
case horizontal_alignment::left:
alignment_node.add_attribute("horizontal", "left");
break;
case alignment::horizontal_alignment::right:
case horizontal_alignment::right:
alignment_node.add_attribute("horizontal", "right");
break;
default:

View File

@ -0,0 +1,86 @@
// Copyright (c) 2014-2015 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/styles/alignment.hpp>
namespace xlnt {
bool alignment::get_wrap_text() const
{
return wrap_text_;
}
void alignment::set_wrap_text(bool wrap_text)
{
wrap_text_ = wrap_text;
}
bool alignment::has_horizontal() const
{
return horizontal_ != horizontal_alignment::none;
}
horizontal_alignment alignment::get_horizontal() const
{
return horizontal_;
}
void alignment::set_horizontal(horizontal_alignment horizontal)
{
horizontal_ = horizontal;
}
bool alignment::has_vertical() const
{
return vertical_ != vertical_alignment::none;
}
vertical_alignment alignment::get_vertical() const
{
return vertical_;
}
void alignment::set_vertical(vertical_alignment vertical)
{
vertical_ = vertical;
}
bool alignment::operator==(const alignment &other) const
{
return hash() == other.hash();
}
std::size_t alignment::hash() const
{
std::size_t seed = 0;
hash_combine(seed, wrap_text_);
hash_combine(seed, shrink_to_fit_);
hash_combine(seed, static_cast<std::size_t>(horizontal_));
hash_combine(seed, static_cast<std::size_t>(vertical_));
hash_combine(seed, text_rotation_);
hash_combine(seed, indent_);
return seed;
}
} // namespace xlnt

36
source/styles/border.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <xlnt/styles/border.hpp>
namespace xlnt {
bool border::operator==(const border &other) const
{
return hash() == other.hash();
}
std::size_t border::hash() const
{
std::size_t seed = 0;
hash_combine(seed, start_assigned);
if (start_assigned) hash_combine(seed, start.hash());
hash_combine(seed, end_assigned);
if (end_assigned) hash_combine(seed, end.hash());
hash_combine(seed, left_assigned);
if (left_assigned) hash_combine(seed, left.hash());
hash_combine(seed, right_assigned);
if (right_assigned) hash_combine(seed, right.hash());
hash_combine(seed, top_assigned);
if (top_assigned) hash_combine(seed, top.hash());
hash_combine(seed, bottom_assigned);
if (bottom_assigned) hash_combine(seed, bottom.hash());
hash_combine(seed, diagonal_assigned);
if (diagonal_assigned) hash_combine(seed, diagonal.hash());
hash_combine(seed, vertical_assigned);
if (vertical_assigned) hash_combine(seed, vertical.hash());
hash_combine(seed, horizontal_assigned);
if (horizontal_assigned) hash_combine(seed, horizontal.hash());
return seed;
}
} // namespace xlnt

View File

@ -1,6 +1,7 @@
#include <algorithm>
#include <regex>
#include <xlnt/utils/datetime.hpp>
#include <xlnt/utils/hash_combine.hpp>
#include <xlnt/styles/number_format.hpp>
@ -65,6 +66,764 @@ const std::unordered_map<std::size_t, std::string> &builtin_formats()
return *formats;
}
enum class condition_type
{
less_than,
less_or_equal,
equal,
greater_than,
greater_or_equal,
invalid
};
struct section
{
bool has_value = false;
std::string value;
bool has_color = false;
std::string color;
bool has_condition = false;
condition_type condition = condition_type::invalid;
std::string condition_value;
bool has_locale = false;
std::string locale;
section &operator=(const section &other)
{
has_value = other.has_value;
value = other.value;
has_color = other.has_color;
color = other.color;
has_condition = other.has_condition;
condition = other.condition;
condition_value = other.condition_value;
has_locale = other.has_locale;
locale = other.locale;
return *this;
}
};
struct format_sections
{
section first;
section second;
section third;
section fourth;
};
// copied from named_range.cpp, keep in sync
/// <summary>
/// Return a vector containing string split at each delim.
/// </summary>
/// <remark>
/// This should maybe be in a utility header so it can be used elsewhere.
/// </remarks>
std::vector<std::string> split_string(const std::string &string, char delim)
{
std::vector<std::string> split;
std::string::size_type previous_index = 0;
auto separator_index = string.find(delim);
while (separator_index != std::string::npos)
{
auto part = string.substr(previous_index, separator_index - previous_index);
split.push_back(part);
previous_index = separator_index + 1;
separator_index = string.find(delim, previous_index);
}
split.push_back(string.substr(previous_index));
return split;
}
std::vector<std::string> split_string_any(const std::string &string, const std::string &delims)
{
std::vector<std::string> split;
std::string::size_type previous_index = 0;
auto separator_index = string.find_first_of(delims);
while (separator_index != std::string::npos)
{
auto part = string.substr(previous_index, separator_index - previous_index);
if (!part.empty())
{
split.push_back(part);
}
previous_index = separator_index + 1;
separator_index = string.find_first_of(delims, previous_index);
}
split.push_back(string.substr(previous_index));
return split;
}
bool is_date_format(const std::string &format_string)
{
auto not_in = format_string.find_first_not_of("/-:, mMyYdDhHsS");
return not_in == std::string::npos;
}
bool is_valid_color(const std::string &color)
{
static const std::vector<std::string> *colors =
new std::vector<std::string>(
{
"Black",
"Green"
"White",
"Blue",
"Magenta",
"Yellow",
"Cyan",
"Red"
});
auto compare_color = [&](const std::string &other) {
if (color.size() != other.size()) return false;
for (std::size_t i = 0; i < color.size(); i++)
{
if (std::toupper(color[i]) != std::toupper(other[i]))
{
return false;
}
}
return true;
};
return std::find_if(colors->begin(), colors->end(), compare_color) != colors->end();
}
bool parse_condition(const std::string &string, section &s)
{
s.has_condition = false;
s.condition = condition_type::invalid;
s.condition_value.clear();
if (string[0] == '<')
{
s.has_condition = true;
if (string[1] == '=')
{
s.condition = condition_type::less_or_equal;
s.condition_value = string.substr(2);
}
else
{
s.condition = condition_type::less_than;
s.condition_value = string.substr(1);
}
}
if (string[0] == '>')
{
s.has_condition = true;
if (string[1] == '=')
{
s.condition = condition_type::greater_or_equal;
s.condition_value = string.substr(2);
}
else
{
s.condition = condition_type::greater_than;
s.condition_value = string.substr(1);
}
}
else if (string[0] == '=')
{
s.has_condition = true;
s.condition = condition_type::equal;
s.condition_value = string.substr(1);
}
return s.has_condition;
}
bool is_hex(char c)
{
if (c >= 'A' || c <= 'F') return true;
if (c >= '0' || c <= '9') return true;
return false;
}
const std::unordered_map<int, std::string> known_locales()
{
const std::unordered_map<int, std::string> *all =
new std::unordered_map<int, std::string>(
{
{ 0x401, "Arabic - Saudi Arabia" },
{ 0x402, "Bulgarian" },
{ 0x403, "Catalan" },
{ 0x404, "Chinese - Taiwan" },
{ 0x405, "Czech" },
{ 0x406, "Danish" },
{ 0x407, "German - Germany" },
{ 0x408, "Greek" },
{ 0x409, "English - United States" },
{ 0x410, "Italian - Italy" },
{ 0x411, "Japanese" },
{ 0x412, "Korean" },
{ 0x413, "Dutch - Netherlands" },
{ 0x414, "Norwegian - Bokml" },
{ 0x415, "Polish" },
{ 0x416, "Portuguese - Brazil" },
{ 0x417, "Raeto-Romance" },
{ 0x418, "Romanian - Romania" },
{ 0x419, "Russian" },
{ 0x420, "Urdu" },
{ 0x421, "Indonesian" },
{ 0x422, "Ukrainian" },
{ 0x423, "Belarusian" },
{ 0x424, "Slovenian" },
{ 0x425, "Estonian" },
{ 0x426, "Latvian" },
{ 0x427, "Lithuanian" },
{ 0x428, "Tajik" },
{ 0x429, "Farsi - Persian" },
{ 0x430, "Sesotho (Sutu)" },
{ 0x431, "Tsonga" },
{ 0x432, "Setsuana" },
{ 0x433, "Venda" },
{ 0x434, "Xhosa" },
{ 0x435, "Zulu" },
{ 0x436, "Afrikaans" },
{ 0x437, "Georgian" },
{ 0x438, "Faroese" },
{ 0x439, "Hindi" },
{ 0x440, "Kyrgyz - Cyrillic" },
{ 0x441, "Swahili" },
{ 0x442, "Turkmen" },
{ 0x443, "Uzbek - Latin" },
{ 0x444, "Tatar" },
{ 0x445, "Bengali - India" },
{ 0x446, "Punjabi" },
{ 0x447, "Gujarati" },
{ 0x448, "Oriya" },
{ 0x449, "Tamil" },
{ 0x450, "Mongolian" },
{ 0x451, "Tibetan" },
{ 0x452, "Welsh" },
{ 0x453, "Khmer" },
{ 0x454, "Lao" },
{ 0x455, "Burmese" },
{ 0x456, "Galician" },
{ 0x457, "Konkani" },
{ 0x458, "Manipuri" },
{ 0x459, "Sindhi" },
{ 0x460, "Kashmiri" },
{ 0x461, "Nepali" },
{ 0x462, "Frisian - Netherlands" },
{ 0x464, "Filipino" },
{ 0x465, "Divehi; Dhivehi; Maldivian" },
{ 0x466, "Edo" },
{ 0x470, "Igbo - Nigeria" },
{ 0x474, "Guarani - Paraguay" },
{ 0x476, "Latin" },
{ 0x477, "Somali" },
{ 0x481, "Maori" },
{ 0x801, "Arabic - Iraq" },
{ 0x804, "Chinese - China" },
{ 0x807, "German - Switzerland" },
{ 0x809, "English - Great Britain" },
{ 0x810, "Italian - Switzerland" },
{ 0x813, "Dutch - Belgium" },
{ 0x814, "Norwegian - Nynorsk" },
{ 0x816, "Portuguese - Portugal" },
{ 0x818, "Romanian - Moldova" },
{ 0x819, "Russian - Moldova" },
{ 0x843, "Uzbek - Cyrillic" },
{ 0x845, "Bengali - Bangladesh" },
{ 0x850, "Mongolian" },
{ 0x1001, "Arabic - Libya" },
{ 0x1004, "Chinese - Singapore" },
{ 0x1007, "German - Luxembourg" },
{ 0x1009, "English - Canada" },
{ 0x1401, "Arabic - Algeria" },
{ 0x1404, "Chinese - Macau SAR" },
{ 0x1407, "German - Liechtenstein" },
{ 0x1409, "English - New Zealand" },
{ 0x1801, "Arabic - Morocco" },
{ 0x1809, "English - Ireland" },
{ 0x2001, "Arabic - Oman" },
{ 0x2009, "English - Jamaica" },
{ 0x2401, "Arabic - Yemen" },
{ 0x2409, "English - Caribbean" },
{ 0x2801, "Arabic - Syria" },
{ 0x2809, "English - Belize" },
{ 0x3001, "Arabic - Lebanon" },
{ 0x3009, "English - Zimbabwe" },
{ 0x3401, "Arabic - Kuwait" },
{ 0x3409, "English - Phillippines" },
{ 0x3801, "Arabic - United Arab Emirates" },
{ 0x4001, "Arabic - Qatar" }
});
return *all;
}
bool is_valid_locale(const std::string &locale_string)
{
std::string country = locale_string.substr(locale_string.find('-') + 1);
if (country.empty())
{
return false;
}
for (auto c : country)
{
if (!is_hex(static_cast<char>(std::toupper(c))))
{
return false;
}
}
auto index = std::stoi(country, 0, 16);
auto known_locales_ = known_locales();
if (known_locales_.find(index) == known_locales_.end())
{
return false;
}
std::string beginning = locale_string.substr(0, locale_string.find('-'));
if (beginning.empty() || beginning[0] != '$')
{
return false;
}
if (beginning.size() == 1)
{
return true;
}
beginning = beginning.substr(1);
return true;
}
section parse_section(const std::string &section_string)
{
section s;
std::string format_part;
std::string bracket_part;
std::vector<std::string> bracket_parts;
bool in_quotes = false;
bool in_brackets = false;
const std::vector<std::string> bracket_times = { "h", "hh", "m", "mm", "s", "ss" };
for (std::size_t i = 0; i < section_string.size(); i++)
{
if (!in_quotes && section_string[i] == '"')
{
format_part.push_back(section_string[i]);
in_quotes = true;
}
else if (in_quotes && section_string[i] == '"')
{
format_part.push_back(section_string[i]);
if (i < section_string.size() - 1 && section_string[i + 1] != '"')
{
in_quotes = false;
}
}
else if (!in_brackets && section_string[i] == '[')
{
in_brackets = true;
for (auto bracket_time : bracket_times)
{
if (i < section_string.size() - bracket_time.size() &&
section_string.substr(i + 1, bracket_time.size()) == bracket_time)
{
in_brackets = false;
break;
}
}
}
else if (in_brackets)
{
if (section_string[i] == ']')
{
in_brackets = false;
if (is_valid_color(bracket_part))
{
if (s.color.empty())
{
s.color = bracket_part;
s.has_color = true;
}
else
{
throw std::runtime_error("two colors");
}
}
else if (is_valid_locale(bracket_part))
{
if (s.locale.empty())
{
s.locale = bracket_part;
s.has_locale = true;
}
else
{
throw std::runtime_error("two locales");
}
}
else if (s.has_condition || !parse_condition(bracket_part, s))
{
throw std::runtime_error("invalid bracket format");
}
bracket_part.clear();
}
else
{
bracket_part.push_back(section_string[i]);
}
}
else
{
format_part.push_back(section_string[i]);
}
}
s.value = format_part;
s.has_value = true;
return s;
}
format_sections parse_format_sections(const std::string &combined)
{
format_sections result = {};
auto split = split_string(combined, ';');
if (split.empty())
{
throw std::runtime_error("empty string");
}
result.first = parse_section(split[0]);
if (!result.first.has_condition)
{
result.second = result.first;
result.third = result.first;
}
if (split.size() > 1)
{
result.second = parse_section(split[1]);
}
if (split.size() > 2)
{
if (result.first.has_condition && !result.second.has_condition)
{
throw std::runtime_error("first two sections should have conditions");
}
result.third = parse_section(split[2]);
if (result.third.has_condition)
{
throw std::runtime_error("third section shouldn't have a condition");
}
}
if (split.size() > 3)
{
if (result.first.has_condition)
{
throw std::runtime_error("too many parts");
}
result.fourth = parse_section(split[3]);
}
if (split.size() > 4)
{
throw std::runtime_error("too many parts");
}
return result;
}
std::string format_section(long double number, const section &format, xlnt::calendar base_date)
{
const std::string unquoted = "$+(:^'{<=-/)!&~}> ";
std::string format_temp = format.value;
std::string result;
if (is_date_format(format.value))
{
const std::string date_unquoted = ",-/: ";
const std::vector<std::string> dates = { "m", "mm", "mmm", "mmmmm", "mmmmmm", "d", "dd", "ddd", "dddd", "yy",
"yyyy", "h", "[h]", "hh", "m", "[m]", "mm", "s", "[s]", "ss", "AM/PM",
"am/pm", "A/P", "a/p" };
const std::vector<std::string> MonthNames = { "January", "February", "March",
"April", "May", "June", "July", "August", "September", "October", "November", "December" };
auto split = split_string_any(format.value, date_unquoted);
std::string::size_type index = 0, prev = 0;
auto d = xlnt::datetime::from_number(number, base_date);
bool processed_month = false;
auto lower_string = [](const std::string &s) {
std::string lower;
lower.resize(s.size());
for (std::size_t i = 0; i < s.size(); i++)
lower[i] = static_cast<char>(std::tolower(s[i]));
return lower;
};
for (auto part : split)
{
while (format.value.substr(index, part.size()) != part)
{
index++;
}
auto between = format.value.substr(prev, index - prev);
result.append(between);
part = lower_string(part);
if (part == "m" && !processed_month)
{
result.append(std::to_string(d.month));
processed_month = true;
}
else if (part == "mm" && !processed_month)
{
if (d.month < 10)
{
result.append("0");
}
result.append(std::to_string(d.month));
processed_month = true;
}
else if (part == "mmm" && !processed_month)
{
result.append(MonthNames.at(static_cast<std::size_t>(d.month - 1)).substr(0, 3));
processed_month = true;
}
else if (part == "mmmm" && !processed_month)
{
result.append(MonthNames.at(static_cast<std::size_t>(d.month - 1)));
processed_month = true;
}
else if (part == "d")
{
result.append(std::to_string(d.day));
}
else if (part == "dd")
{
if (d.day < 10)
{
result.append("0");
}
result.append(std::to_string(d.day));
}
else if (part == "yyyy")
{
result.append(std::to_string(d.year));
}
else if (part == "h")
{
result.append(std::to_string(d.hour));
processed_month = true;
}
else if (part == "hh")
{
if (d.hour < 10)
{
result.append("0");
}
result.append(std::to_string(d.hour));
processed_month = true;
}
else if (part == "m")
{
result.append(std::to_string(d.minute));
}
else if (part == "mm")
{
if (d.minute < 10)
{
result.append("0");
}
result.append(std::to_string(d.minute));
}
else if (part == "s")
{
result.append(std::to_string(d.second));
}
else if (part == "ss")
{
if (d.second < 10)
{
result.append("0");
}
result.append(std::to_string(d.second));
}
else if (part == "am/pm" || part == "a/p")
{
if (d.hour < 12)
{
result.append("AM");
}
else
{
result.append("PM");
}
}
index += part.size();
prev = index;
}
if (index < format.value.size())
{
result.append(format.value.substr(index));
}
}
else if (format.value == "General" || format.value == "0")
{
if (number == static_cast<long long int>(number))
{
result = std::to_string(static_cast<long long int>(number));
}
else
{
result = std::to_string(number);
}
}
else if (format.value.substr(0, 8) == "#,##0.00" || format.value.substr(0, 9) == "-#,##0.00")
{
if (format.value[0] == '-')
{
result = "-";
}
if (format.has_locale && format.locale == "$$-1009")
{
result += "CA$";
}
else if (format.has_locale && format.locale == "$€-407")
{
result += "";
}
else
{
result += "$";
}
result += std::to_string(number < 0 ? -number : number);
auto decimal_pos = result.find('.');
if (decimal_pos != std::string::npos)
{
result[decimal_pos] = ',';
decimal_pos += 3;
while (decimal_pos < result.size())
{
result.pop_back();
}
}
}
return result;
}
std::string format_section(const std::string &text, const section &format)
{
auto arobase_index = format.value.find('@');
std::string first_part, middle_part, last_part;
if (arobase_index != std::string::npos)
{
first_part = format.value.substr(0, arobase_index);
middle_part = text;
last_part = format.value.substr(arobase_index + 1);
}
else
{
first_part = format.value;
}
auto unquote = [](std::string &s) {
if (!s.empty())
{
if (s.front() != '"' || s.back() != '"') return false;
s = s.substr(0, s.size() - 2);
}
return true;
};
if (!unquote(first_part) || !unquote(last_part))
{
throw std::runtime_error(std::string("additional text must be enclosed in quotes: ") + format.value);
}
return first_part + middle_part + last_part;
}
std::string format_number(long double number, const std::string &format, xlnt::calendar base_date)
{
auto sections = parse_format_sections(format);
if (number > 0)
{
return format_section(number, sections.first, base_date);
}
else if (number < 0)
{
return format_section(number, sections.second, base_date);
}
// number == 0
return format_section(number, sections.third, base_date);
}
std::string format_text(const std::string &text, const std::string &format)
{
if (format == "General") return text;
auto sections = parse_format_sections(format);
return format_section(text, sections.fourth);
}
} // namespace
namespace xlnt {
@ -340,4 +1099,58 @@ void number_format::set_format_string(const std::string &format_string, std::siz
id_set_ = true;
}
bool number_format::has_id() const
{
return id_set_;
}
void number_format::set_id(std::size_t id)
{
id_ = id;
id_set_ = true;
}
std::size_t number_format::get_id() const
{
if(!id_set_)
{
throw std::runtime_error("number format doesn't have an id");
}
return id_;
}
bool number_format::is_date_format() const
{
if (format_string_ != "General")
{
try
{
auto sections = parse_format_sections(format_string_);
return ::is_date_format(sections.first.value);
}
catch (std::exception)
{
return false;
}
}
return false;
}
std::string number_format::format(const std::string &text) const
{
return format_text(text, format_string_);
}
std::string number_format::format(long double number, calendar base_date) const
{
return format_number(number, format_string_, base_date);
}
bool number_format::operator==(const number_format &other) const
{
return hash() == other.hash();
}
} // namespace xlnt

View File

@ -3,7 +3,130 @@
namespace xlnt {
template <>
cell_vector::iterator::iterator(worksheet ws, const cell_reference &start_cell, major_order order)
: ws_(ws), current_cell_(start_cell), range_(start_cell.to_range()), order_(order)
{
}
cell_vector::iterator::iterator(const iterator &other)
{
*this = other;
}
bool cell_vector::iterator::operator==(const iterator &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool cell_vector::iterator::operator!=(const iterator &other) const
{
return !(*this == other);
}
cell_vector::iterator &cell_vector::iterator::operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
return *this;
}
cell_vector::iterator cell_vector::iterator::operator--(int)
{
iterator old = *this;
--*this;
return old;
}
cell_vector::iterator &cell_vector::iterator::operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
return *this;
}
cell_vector::iterator cell_vector::iterator::operator++(int)
{
iterator old = *this;
++*this;
return old;
}
cell_vector::const_iterator::const_iterator(worksheet ws, const cell_reference &start_cell, major_order order)
: ws_(ws), current_cell_(start_cell), range_(start_cell.to_range()), order_(order)
{
}
cell_vector::const_iterator::const_iterator(const const_iterator &other)
{
*this = other;
}
bool cell_vector::const_iterator::operator==(const const_iterator &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool cell_vector::const_iterator::operator!=(const const_iterator &other) const
{
return !(*this == other);
}
cell_vector::const_iterator &cell_vector::const_iterator::operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
return *this;
}
cell_vector::const_iterator cell_vector::const_iterator::operator--(int)
{
const_iterator old = *this;
--*this;
return old;
}
cell_vector::const_iterator &cell_vector::const_iterator::operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
else
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
return *this;
}
cell_vector::const_iterator cell_vector::const_iterator::operator++(int)
{
const_iterator old = *this;
++*this;
return old;
}
cell cell_vector::iterator::operator*()
{
return ws_[current_cell_];

View File

@ -0,0 +1,34 @@
#include <xlnt/worksheet/footer.hpp>
namespace xlnt {
void footer::set_text(const std::string &text)
{
default_ = false;
text_ = text;
}
void footer::set_font_name(const std::string &font_name)
{
default_ = false;
font_name_ = font_name;
}
void footer::set_font_size(std::size_t font_size)
{
default_ = false;
font_size_ = font_size;
}
void footer::set_font_color(const std::string &font_color)
{
default_ = false;
font_color_ = font_color;
}
bool footer::is_default() const
{
return default_;
}
} // namespace xlnt

View File

@ -0,0 +1,34 @@
#include <xlnt/worksheet/header.hpp>
namespace xlnt {
void header::set_text(const std::string &text)
{
default_ = false;
text_ = text;
}
void header::set_font_name(const std::string &font_name)
{
default_ = false;
font_name_ = font_name;
}
void header::set_font_size(std::size_t font_size)
{
default_ = false;
font_size_ = font_size;
}
void header::set_font_color(const std::string &font_color)
{
default_ = false;
font_color_ = font_color;
}
bool header::is_default() const
{
return default_;
}
} // namespace xlnt

View File

@ -5,8 +5,8 @@
namespace xlnt {
range::range(worksheet ws, const range_reference &reference, major_order order)
: ws_(ws), ref_(reference), order_(order)
range::range(worksheet ws, const range_reference &reference, major_order order, bool skip_null)
: ws_(ws), ref_(reference), order_(order), skip_null_(skip_null)
{
}
@ -133,7 +133,6 @@ range::const_iterator range::cend() const
return const_iterator(ws_, range_reference(top_right, bottom_right), order_);
}
template <>
cell_vector range::iterator::operator*()
{
if (order_ == major_order::row)
@ -148,4 +147,147 @@ cell_vector range::iterator::operator*()
return cell_vector(ws_, reference, order_);
}
range_iterator_2d::range_iterator_2d(worksheet &ws, const range_reference &start_cell, major_order order)
: ws_(ws.d_), current_cell_(start_cell.get_top_left()), range_(start_cell), order_(order)
{
}
range_iterator_2d::range_iterator_2d(const range_iterator_2d &other)
{
*this = other;
}
bool range_iterator_2d::operator==(const range_iterator_2d &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool range_iterator_2d::operator!=(const range_iterator_2d &other) const
{
return !(*this == other);
}
range_iterator_2d &range_iterator_2d::operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
return *this;
}
range_iterator_2d range_iterator_2d::operator--(int)
{
range_iterator_2d old = *this;
--*this;
return old;
}
range_iterator_2d &range_iterator_2d::operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
return *this;
}
range_iterator_2d range_iterator_2d::operator++(int)
{
range_iterator_2d old = *this;
++*this;
return old;
}
const_range_iterator_2d::const_range_iterator_2d(const worksheet &ws, const range_reference &start_cell, major_order order)
: ws_(ws.d_), current_cell_(start_cell.get_top_left()), range_(start_cell), order_(order)
{
}
const_range_iterator_2d::const_range_iterator_2d(const const_range_iterator_2d &other)
{
*this = other;
}
bool const_range_iterator_2d::operator==(const const_range_iterator_2d &other) const
{
return ws_ == other.ws_ && current_cell_ == other.current_cell_ && order_ == other.order_;
}
bool const_range_iterator_2d::operator!=(const const_range_iterator_2d &other) const
{
return !(*this == other);
}
range::const_iterator &range::const_iterator::operator--()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() - 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() - 1);
}
return *this;
}
range::const_iterator range::const_iterator::operator--(int)
{
const_range_iterator_2d old = *this;
--*this;
return old;
}
range::const_iterator &range::const_iterator::operator++()
{
if (order_ == major_order::row)
{
current_cell_.set_row(current_cell_.get_row() + 1);
}
else
{
current_cell_.set_column_index(current_cell_.get_column_index() + 1);
}
return *this;
}
range::const_iterator range::const_iterator::operator++(int)
{
const_range_iterator_2d old = *this;
++*this;
return old;
}
bool range::operator!=(const range &comparand) const
{
return !(*this == comparand);
}
range::const_iterator range::begin() const
{
return cbegin();
}
range::const_iterator range::end() const
{
return cend();
}
} // namespace xlnt

View File

@ -82,4 +82,62 @@ bool range_reference::operator!=(const range_reference &comparand) const
{
return comparand.top_left_ != top_left_ || comparand.bottom_right_ != bottom_right_;
}
cell_reference range_reference::get_top_left() const
{
return top_left_;
}
cell_reference range_reference::get_bottom_right() const
{
return bottom_right_;
}
cell_reference &range_reference::get_top_left()
{
return top_left_;
}
cell_reference &range_reference::get_bottom_right()
{
return bottom_right_;
}
bool range_reference::operator==(const std::string &reference_string) const
{
return *this == range_reference(reference_string);
}
bool range_reference::operator==(const char *reference_string) const
{
return *this == std::string(reference_string);
}
bool range_reference::operator!=(const std::string &reference_string) const
{
return *this != range_reference(reference_string);
}
bool range_reference::operator!=(const char *reference_string) const
{
return *this != std::string(reference_string);
}
XLNT_FUNCTION bool operator==(const std::string &reference_string, const range_reference &ref)
{
return ref == reference_string;
}
XLNT_FUNCTION bool operator==(const char *reference_string, const range_reference &ref)
{
return ref == reference_string;
}
XLNT_FUNCTION bool operator!=(const std::string &reference_string, const range_reference &ref)
{
return ref != reference_string;
}
XLNT_FUNCTION bool operator!=(const char *reference_string, const range_reference &ref)
{
return ref != reference_string;
}
} // namespace xlnt

View File

@ -4,6 +4,18 @@
#include <xlnt/worksheet/sheet_protection.hpp>
namespace {
template <typename T>
std::string int_to_hex(T i)
{
std::stringstream stream;
stream << std::hex << i;
return stream.str();
}
} // namespace
namespace xlnt {
void sheet_protection::set_password(const std::string &password)
@ -11,12 +23,9 @@ void sheet_protection::set_password(const std::string &password)
hashed_password_ = hash_password(password);
}
template <typename T>
std::string int_to_hex(T i)
std::string sheet_protection::get_hashed_password() const
{
std::stringstream stream;
stream << std::hex << i;
return stream.str();
return hashed_password_;
}
std::string sheet_protection::hash_password(const std::string &plaintext_password)

View File

@ -192,8 +192,16 @@ public:
ws.garbage_collect();
auto cell_collection = ws.get_cell_collection();
std::set<xlnt::cell> cells(cell_collection.begin(), cell_collection.end());
std::set<xlnt::cell> cells;
for(auto row : ws)
{
for(auto cell : row)
{
if(!cell.garbage_collectible()) cells.insert(cell);
}
}
std::set<xlnt::cell> expected = {ws.get_cell("B2"), ws.get_cell("C4"), ws.get_cell("D1")};
// Set difference

View File

@ -3,7 +3,7 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/cell/types.hpp>
#include <xlnt/cell/index_types.hpp>
#include <xlnt/packaging/relationship.hpp>
#include <xlnt/utils/date.hpp>
#include <xlnt/utils/datetime.hpp>
@ -173,19 +173,6 @@ void worksheet::garbage_collect()
}
}
std::list<cell> worksheet::get_cell_collection()
{
std::list<cell> cells;
for (auto &c : d_->cell_map_)
{
for (auto &d : c.second)
{
cells.push_back(cell(&d.second));
}
}
return cells;
}
std::string worksheet::get_title() const
{
if (d_ == nullptr)
@ -766,4 +753,57 @@ const row_properties &worksheet::get_row_properties(row_t row) const
return d_->row_properties_.at(row);
}
worksheet::iterator worksheet::begin()
{
auto dimensions = calculate_dimension();
cell_reference top_right(dimensions.get_bottom_right().get_column_index(), dimensions.get_top_left().get_row());
range_reference row_range(dimensions.get_top_left(), top_right);
return iterator(*this, row_range, major_order::row);
}
worksheet::iterator worksheet::end()
{
auto dimensions = calculate_dimension();
auto past_end_row_index = dimensions.get_bottom_right().get_row() + 1;
cell_reference bottom_left(dimensions.get_top_left().get_column_index(), past_end_row_index);
cell_reference bottom_right(dimensions.get_bottom_right().get_column_index(), past_end_row_index);
return iterator(*this, range_reference(bottom_left, bottom_right), major_order::row);
}
worksheet::const_iterator worksheet::cbegin() const
{
auto dimensions = calculate_dimension();
cell_reference top_right(dimensions.get_bottom_right().get_column_index(), dimensions.get_top_left().get_row());
range_reference row_range(dimensions.get_top_left(), top_right);
return const_iterator(*this, row_range, major_order::row);
}
worksheet::const_iterator worksheet::cend() const
{
auto dimensions = calculate_dimension();
auto past_end_row_index = dimensions.get_bottom_right().get_row() + 1;
cell_reference bottom_left(dimensions.get_top_left().get_column_index(), past_end_row_index);
cell_reference bottom_right(dimensions.get_bottom_right().get_column_index(), past_end_row_index);
return const_iterator(*this, range_reference(bottom_left, bottom_right), major_order::row);
}
worksheet::const_iterator worksheet::begin() const
{
return cbegin();
}
worksheet::const_iterator worksheet::end() const
{
return cend();
}
range worksheet::iter_cells(bool skip_null)
{
return range(*this, calculate_dimension(), major_order::row, skip_null);
}
} // namespace xlnt