general API improvements

This commit is contained in:
Thomas Fussell 2016-05-11 19:24:53 -04:00
parent 720edc143f
commit 31b546b1d5
15 changed files with 414 additions and 170 deletions

View File

@ -44,6 +44,7 @@ class font;
class number_format; class number_format;
class protection; class protection;
class relationship; class relationship;
class workbook;
class worksheet; class worksheet;
struct date; struct date;
@ -329,16 +330,26 @@ public:
/// <summary> /// <summary>
/// Return the worksheet that owns this cell. /// Return the worksheet that owns this cell.
/// </summary> /// </summary>
worksheet get_parent(); worksheet get_worksheet();
/// <summary> /// <summary>
/// Return the worksheet that owns this cell. /// Return the worksheet that owns this cell.
/// </summary> /// </summary>
const worksheet get_parent() const; const worksheet get_worksheet() const;
/// <summary>
/// Return the workbook of the worksheet that owns this cell.
/// </summary>
workbook &get_workbook();
/// <summary>
/// Return the workbook of the worksheet that owns this cell.
/// </summary>
const workbook &get_workbook() const;
/// <summary> /// <summary>
/// Shortcut to return the base date of the parent workbook. /// Shortcut to return the base date of the parent workbook.
/// Equivalent to get_parent().get_parent().get_properties().excel_base_date /// Equivalent to get_workbook().get_properties().excel_base_date
/// </summary> /// </summary>
calendar get_base_date() const; calendar get_base_date() const;
@ -390,6 +401,8 @@ private:
friend class worksheet; friend class worksheet;
friend struct detail::cell_impl; friend struct detail::cell_impl;
void guess_type_and_set_value(const std::string &value);
/// <summary> /// <summary>
/// Private constructor to create a cell from its implementation. /// Private constructor to create a cell from its implementation.
/// </summary> /// </summary>

View File

@ -0,0 +1,62 @@
// Copyright (c) 2014-2016 Thomas Fussell
// Copyright (c) 2010-2015 openpyxl
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/cell/text.hpp>
#include <xlnt/cell/text_run.hpp>
namespace xlnt {
void text::clear()
{
runs_.clear();
}
void text::set_plain_string(const std::string &s)
{
clear();
add_run(text_run(s));
}
std::string text::get_plain_string() const
{
std::string plain_string;
for (const auto &run : runs_)
{
plain_string.append(run.get_string());
}
return plain_string;
}
std::vector<text_run> text::get_runs()
{
return runs_;
}
void text::add_run(const text_run &t)
{
runs_.push_back(t);
}
} // namespace xlnt

View File

@ -0,0 +1,49 @@
// Copyright (c) 2016 Thomas Fussell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#pragma once
#include <string>
#include <vector>
#include <xlnt/xlnt_config.hpp> // for XLNT_CLASS, XLNT_FUNCTION
#include <xlnt/cell/text_run.hpp>
namespace xlnt {
class text_run;
class XLNT_CLASS text
{
public:
void clear();
void set_plain_string(const std::string &s);
std::string get_plain_string() const;
std::vector<text_run> get_runs();
void add_run(const text_run &t);
void set_run(const std::vector<text_run> &parts);
private:
std::vector<text_run> runs_;
};
} // namespace xlnt

View File

@ -0,0 +1,46 @@
// Copyright (c) 2014-2016 Thomas Fussell
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file
#include <xlnt/cell/text_run.hpp>
namespace xlnt {
text_run::text_run() : text_run("")
{
}
text_run::text_run(const std::string &string) : string_(string)
{
}
std::string text_run::get_string() const
{
return string_;
}
void text_run::set_string(const std::string &string)
{
string_ = string;
}
} // namespace xlnt

View File

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

View File

@ -72,7 +72,8 @@ public:
worksheet(workbook &parent_workbook, const std::string &title = std::string()); worksheet(workbook &parent_workbook, const std::string &title = std::string());
std::string to_string() const; std::string to_string() const;
workbook &get_parent() const; workbook &get_workbook();
const workbook &get_workbook() const;
void garbage_collect(); void garbage_collect();
// title // title

View File

@ -27,6 +27,7 @@
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp> #include <xlnt/cell/cell_reference.hpp>
#include <xlnt/cell/comment.hpp> #include <xlnt/cell/comment.hpp>
#include <xlnt/cell/text.hpp>
#include <xlnt/packaging/document_properties.hpp> #include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/relationship.hpp> #include <xlnt/packaging/relationship.hpp>
#include <xlnt/serialization/encoding.hpp> #include <xlnt/serialization/encoding.hpp>
@ -46,6 +47,77 @@
#include <detail/cell_impl.hpp> #include <detail/cell_impl.hpp>
#include <detail/comment_impl.hpp> #include <detail/comment_impl.hpp>
namespace {
std::pair<bool, long double> cast_numeric(const std::string &s)
{
const char *str = s.c_str();
char *str_end = nullptr;
auto result = std::strtold(str, &str_end);
if (str_end != str + s.size()) return{ false, 0 };
return{ true, result };
}
std::pair<bool, long double> cast_percentage(const std::string &s)
{
if (s.back() == '%')
{
auto number = cast_numeric(s.substr(0, s.size() - 1));
if (number.first)
{
return{ true, number.second / 100 };
}
}
return{ false, 0 };
}
std::pair<bool, xlnt::time> cast_time(const std::string &s)
{
xlnt::time result;
try
{
auto last_colon = s.find_last_of(':');
if (last_colon == std::string::npos) return{ false, result };
double seconds = std::stod(s.substr(last_colon + 1));
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find_first_of(':');
if (first_colon == last_colon)
{
auto decimal_pos = s.find('.');
if (decimal_pos != std::string::npos)
{
result.minute = std::stoi(s.substr(0, first_colon));
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = result.second;
result.second = 0;
}
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
}
}
catch (std::invalid_argument)
{
return{ false, result };
}
return{ true, result };
}
} // namespace
namespace xlnt { namespace xlnt {
const std::unordered_map<std::string, int> &cell::error_codes() const std::unordered_map<std::string, int> &cell::error_codes()
@ -68,7 +140,7 @@ std::string cell::check_string(const std::string &to_check)
return s; return s;
} }
auto wb_encoding = get_parent().get_parent().get_encoding(); auto wb_encoding = get_workbook().get_encoding();
//XXX: use utfcpp for this! //XXX: use utfcpp for this!
switch(wb_encoding) switch(wb_encoding)
@ -263,14 +335,42 @@ XLNT_FUNCTION void cell::set_value(long double d)
d_->type_ = type::numeric; d_->type_ = type::numeric;
} }
template <>
XLNT_FUNCTION void cell::set_value(text t)
{
d_->value_text_ = t;
d_->type_ = type::string;
if (!t.get_plain_string().empty())
{
get_workbook().add_shared_string(t.get_plain_string());
}
}
template <> template <>
XLNT_FUNCTION void cell::set_value(std::string s) XLNT_FUNCTION void cell::set_value(std::string s)
{ {
d_->set_string(check_string(s), get_parent().get_parent().get_guess_types()); s = check_string(s);
if (get_data_type() == type::string && !s.empty()) if (s.size() > 1 && s.front() == '=')
{ {
get_parent().get_parent().add_shared_string(s); d_->type_ = type::formula;
set_formula(s);
}
else if (cell::error_codes().find(s) != cell::error_codes().end())
{
set_error(s);
}
else
{
text t;
t.set_plain_string(s);
set_value(t);
}
if (get_workbook().get_guess_types())
{
guess_type_and_set_value(s);
} }
} }
@ -285,7 +385,7 @@ XLNT_FUNCTION void cell::set_value(cell c)
{ {
d_->type_ = c.d_->type_; d_->type_ = c.d_->type_;
d_->value_numeric_ = c.d_->value_numeric_; d_->value_numeric_ = c.d_->value_numeric_;
d_->value_string_ = c.d_->value_string_; d_->value_text_ = c.d_->value_text_;
d_->hyperlink_ = c.d_->hyperlink_; d_->hyperlink_ = c.d_->hyperlink_;
d_->has_hyperlink_ = c.d_->has_hyperlink_; d_->has_hyperlink_ = c.d_->has_hyperlink_;
d_->formula_ = c.d_->formula_; d_->formula_ = c.d_->formula_;
@ -458,7 +558,7 @@ void cell::set_comment(const xlnt::comment &c)
if (!has_comment()) if (!has_comment())
{ {
get_parent().increment_comments(); get_worksheet().increment_comments();
} }
*get_comment().d_ = *c.d_; *get_comment().d_ = *c.d_;
@ -468,7 +568,7 @@ void cell::clear_comment()
{ {
if (has_comment()) if (has_comment())
{ {
get_parent().decrement_comments(); get_worksheet().decrement_comments();
} }
d_->comment_ = nullptr; d_->comment_ = nullptr;
@ -486,31 +586,40 @@ void cell::set_error(const std::string &error)
throw data_type_exception(); throw data_type_exception();
} }
d_->value_string_ = error; d_->value_text_.set_plain_string(error);
d_->type_ = type::error; d_->type_ = type::error;
} }
cell cell::offset(int column, int row) cell cell::offset(int column, int row)
{ {
return get_parent().get_cell(cell_reference(d_->column_ + column, d_->row_ + row)); return get_worksheet().get_cell(cell_reference(d_->column_ + column, d_->row_ + row));
} }
worksheet cell::get_parent() worksheet cell::get_worksheet()
{ {
return worksheet(d_->parent_); return worksheet(d_->parent_);
} }
const worksheet cell::get_parent() const const worksheet cell::get_worksheet() const
{ {
return worksheet(d_->parent_); return worksheet(d_->parent_);
} }
workbook &cell::get_workbook()
{
return get_worksheet().get_workbook();
}
const workbook &cell::get_workbook() const
{
return get_worksheet().get_workbook();
}
comment cell::get_comment() comment cell::get_comment()
{ {
if (d_->comment_ == nullptr) if (d_->comment_ == nullptr)
{ {
d_->comment_.reset(new detail::comment_impl()); d_->comment_.reset(new detail::comment_impl());
get_parent().increment_comments(); get_worksheet().increment_comments();
} }
return comment(d_->comment_.get()); return comment(d_->comment_.get());
@ -533,9 +642,9 @@ std::pair<int, int> cell::get_anchor() const
for (column_t column_index = 1; column_index <= left_columns; column_index++) for (column_t column_index = 1; column_index <= left_columns; column_index++)
{ {
if (get_parent().has_column_properties(column_index)) if (get_worksheet().has_column_properties(column_index))
{ {
auto cdw = get_parent().get_column_properties(column_index).width; auto cdw = get_worksheet().get_column_properties(column_index).width;
if (cdw > 0) if (cdw > 0)
{ {
@ -553,9 +662,9 @@ std::pair<int, int> cell::get_anchor() const
for (row_t row_index = 1; row_index <= top_rows; row_index++) for (row_t row_index = 1; row_index <= top_rows; row_index++)
{ {
if (get_parent().has_row_properties(row_index)) if (get_worksheet().has_row_properties(row_index))
{ {
auto rdh = get_parent().get_row_properties(row_index).height; auto rdh = get_worksheet().get_row_properties(row_index).height;
if (rdh > 0) if (rdh > 0)
{ {
@ -584,11 +693,11 @@ const number_format &cell::get_number_format() const
{ {
if (d_->has_style_) if (d_->has_style_)
{ {
return get_parent().get_parent().get_number_format(d_->style_id_); return get_workbook().get_number_format(d_->style_id_);
} }
else else
{ {
return get_parent().get_parent().get_number_formats().front(); return get_workbook().get_number_formats().front();
} }
} }
@ -596,33 +705,33 @@ const font &cell::get_font() const
{ {
if (d_->has_style_) if (d_->has_style_)
{ {
auto font_id = get_parent().get_parent().get_cell_formats()[d_->style_id_].get_font_id(); auto font_id = get_workbook().get_cell_formats()[d_->style_id_].get_font_id();
return get_parent().get_parent().get_font(font_id); return get_workbook().get_font(font_id);
} }
else else
{ {
return get_parent().get_parent().get_font(0); return get_workbook().get_font(0);
} }
} }
const fill &cell::get_fill() const const fill &cell::get_fill() const
{ {
return get_parent().get_parent().get_fill(get_parent().get_parent().get_cell_format(d_->style_id_).get_fill_id()); return get_workbook().get_fill(get_workbook().get_cell_format(d_->style_id_).get_fill_id());
} }
const border &cell::get_border() const const border &cell::get_border() const
{ {
return get_parent().get_parent().get_border(get_parent().get_parent().get_cell_format(d_->style_id_).get_border_id()); return get_workbook().get_border(get_workbook().get_cell_format(d_->style_id_).get_border_id());
} }
const alignment &cell::get_alignment() const const alignment &cell::get_alignment() const
{ {
return get_parent().get_parent().get_alignment(d_->style_id_); return get_workbook().get_alignment(d_->style_id_);
} }
const protection &cell::get_protection() const const protection &cell::get_protection() const
{ {
return get_parent().get_parent().get_protection(d_->style_id_); return get_workbook().get_protection(d_->style_id_);
} }
bool cell::pivot_button() const bool cell::pivot_button() const
@ -638,7 +747,7 @@ bool cell::quote_prefix() const
void cell::clear_value() void cell::clear_value()
{ {
d_->value_numeric_ = 0; d_->value_numeric_ = 0;
d_->value_string_.clear(); d_->value_text_.clear();
d_->formula_.clear(); d_->formula_.clear();
d_->type_ = cell::type::null; d_->type_ = cell::type::null;
} }
@ -750,43 +859,43 @@ XLNT_FUNCTION timedelta cell::get_value() const
void cell::set_border(const xlnt::border &border_) void cell::set_border(const xlnt::border &border_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_border(border_, d_->style_id_); d_->style_id_ = get_workbook().set_border(border_, d_->style_id_);
} }
void cell::set_fill(const xlnt::fill &fill_) void cell::set_fill(const xlnt::fill &fill_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_fill(fill_, d_->style_id_); d_->style_id_ = get_workbook().set_fill(fill_, d_->style_id_);
} }
void cell::set_font(const font &font_) void cell::set_font(const font &font_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_font(font_, d_->style_id_); d_->style_id_ = get_workbook().set_font(font_, d_->style_id_);
} }
void cell::set_number_format(const number_format &number_format_) void cell::set_number_format(const number_format &number_format_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_number_format(number_format_, d_->style_id_); d_->style_id_ = get_workbook().set_number_format(number_format_, d_->style_id_);
} }
void cell::set_alignment(const xlnt::alignment &alignment_) void cell::set_alignment(const xlnt::alignment &alignment_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_alignment(alignment_, d_->style_id_); d_->style_id_ = get_workbook().set_alignment(alignment_, d_->style_id_);
} }
void cell::set_protection(const xlnt::protection &protection_) void cell::set_protection(const xlnt::protection &protection_)
{ {
d_->has_style_ = true; d_->has_style_ = true;
d_->style_id_ = get_parent().get_parent().set_protection(protection_, d_->style_id_); d_->style_id_ = get_workbook().set_protection(protection_, d_->style_id_);
} }
template <> template <>
XLNT_FUNCTION std::string cell::get_value() const XLNT_FUNCTION std::string cell::get_value() const
{ {
return d_->value_string_; return d_->value_text_.get_plain_string();
} }
bool cell::has_value() const bool cell::has_value() const
@ -833,7 +942,7 @@ void cell::set_style_id(std::size_t style_id)
calendar cell::get_base_date() const calendar cell::get_base_date() const
{ {
return get_parent().get_parent().get_properties().excel_base_date; return get_workbook().get_properties().excel_base_date;
} }
std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell) std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
@ -851,4 +960,37 @@ void cell::set_quote_prefix(bool b)
d_->quote_prefix_ = b; d_->quote_prefix_ = b;
} }
void cell::guess_type_and_set_value(const std::string &value)
{
auto percentage = cast_percentage(value);
if (percentage.first)
{
d_->value_numeric_ = percentage.second;
d_->type_ = cell::type::numeric;
set_number_format(xlnt::number_format::percentage());
}
else
{
auto time = cast_time(value);
if (time.first)
{
d_->type_ = cell::type::numeric;
set_number_format(number_format::date_time6());
d_->value_numeric_ = time.second.to_number();
}
else
{
auto numeric = cast_numeric(value);
if (numeric.first)
{
d_->value_numeric_ = numeric.second;
d_->type_ = cell::type::numeric;
}
}
}
}
} // namespace xlnt } // namespace xlnt

View File

@ -391,7 +391,7 @@ public:
void test_number_format() void test_number_format()
{ {
auto ws = wb.create_sheet(); auto ws = wb.create_sheet();
ws.get_parent().add_number_format(xlnt::number_format("dd--hh--mm")); ws.get_workbook().add_number_format(xlnt::number_format("dd--hh--mm"));
xlnt::cell cell(ws, "A1"); xlnt::cell cell(ws, "A1");
cell.set_number_format(xlnt::number_format("dd--hh--mm")); cell.set_number_format(xlnt::number_format("dd--hh--mm"));

View File

@ -26,76 +26,6 @@
#include "cell_impl.hpp" #include "cell_impl.hpp"
#include "comment_impl.hpp" #include "comment_impl.hpp"
namespace {
std::pair<bool, long double> cast_numeric(const std::string &s)
{
const char *str = s.c_str();
char *str_end = nullptr;
auto result = std::strtold(str, &str_end);
if (str_end != str + s.size()) return { false, 0 };
return { true, result };
}
std::pair<bool, long double> cast_percentage(const std::string &s)
{
if (s.back() == '%')
{
auto number = cast_numeric(s.substr(0, s.size() - 1));
if (number.first)
{
return { true, number.second / 100 };
}
}
return { false, 0 };
}
std::pair<bool, xlnt::time> cast_time(const std::string &s)
{
xlnt::time result;
try
{
auto last_colon = s.find_last_of(':');
if (last_colon == std::string::npos) return { false, result };
double seconds = std::stod(s.substr(last_colon + 1));
result.second = static_cast<int>(seconds);
result.microsecond = static_cast<int>((seconds - static_cast<double>(result.second)) * 1e6);
auto first_colon = s.find_first_of(':');
if (first_colon == last_colon)
{
auto decimal_pos = s.find('.');
if (decimal_pos != std::string::npos)
{
result.minute = std::stoi(s.substr(0, first_colon));
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = result.second;
result.second = 0;
}
}
else
{
result.hour = std::stoi(s.substr(0, first_colon));
result.minute = std::stoi(s.substr(first_colon + 1, last_colon - first_colon - 1));
}
}
catch (std::invalid_argument)
{
return { false, result };
}
return { true, result };
}
} // namespace
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
@ -130,7 +60,7 @@ cell_impl &cell_impl::operator=(const cell_impl &rhs)
{ {
parent_ = rhs.parent_; parent_ = rhs.parent_;
value_numeric_ = rhs.value_numeric_; value_numeric_ = rhs.value_numeric_;
value_string_ = rhs.value_string_; value_text_ = rhs.value_text_;
hyperlink_ = rhs.hyperlink_; hyperlink_ = rhs.hyperlink_;
formula_ = rhs.formula_; formula_ = rhs.formula_;
column_ = rhs.column_; column_ = rhs.column_;
@ -154,54 +84,5 @@ cell cell_impl::self()
return xlnt::cell(this); return xlnt::cell(this);
} }
void cell_impl::set_string(const std::string &s, bool guess_types)
{
value_string_ = s;
type_ = cell::type::string;
if (value_string_.size() > 1 && value_string_.front() == '=')
{
formula_ = value_string_;
type_ = cell::type::formula;
value_string_.clear();
}
else if (cell::error_codes().find(s) != cell::error_codes().end())
{
type_ = cell::type::error;
}
else if (guess_types)
{
auto percentage = cast_percentage(s);
if (percentage.first)
{
value_numeric_ = percentage.second;
type_ = cell::type::numeric;
self().set_number_format(xlnt::number_format::percentage());
}
else
{
auto time = cast_time(s);
if (time.first)
{
type_ = cell::type::numeric;
self().set_number_format(number_format::date_time6());
value_numeric_ = time.second.to_number();
}
else
{
auto numeric = cast_numeric(s);
if (numeric.first)
{
value_numeric_ = numeric.second;
type_ = cell::type::numeric;
}
}
}
}
}
} // namespace detail } // namespace detail
} // namespace xlnt } // namespace xlnt

View File

@ -25,6 +25,7 @@
#include <cstdlib> #include <cstdlib>
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/cell/text.hpp>
#include <xlnt/cell/comment.hpp> #include <xlnt/cell/comment.hpp>
#include <xlnt/cell/index_types.hpp> #include <xlnt/cell/index_types.hpp>
#include <xlnt/utils/exceptions.hpp> #include <xlnt/utils/exceptions.hpp>
@ -52,8 +53,6 @@ struct cell_impl
cell self(); cell self();
void set_string(const std::string &s, bool guess_types);
cell::type type_; cell::type type_;
worksheet_impl *parent_; worksheet_impl *parent_;
@ -61,7 +60,7 @@ struct cell_impl
column_t column_; column_t column_;
row_t row_; row_t row_;
std::string value_string_; text value_text_;
long double value_numeric_; long double value_numeric_;
std::string formula_; std::string formula_;

View File

@ -335,7 +335,7 @@ public:
auto ws = wb.get_active_sheet(); auto ws = wb.get_active_sheet();
TS_ASSERT(ws.get_formula_attributes().empty()); TS_ASSERT(ws.get_formula_attributes().empty());
TS_ASSERT(ws.get_parent().get_data_only()); TS_ASSERT(ws.get_workbook().get_data_only());
TS_ASSERT(ws.get_cell("A2").get_data_type() == xlnt::cell::type::numeric); TS_ASSERT(ws.get_cell("A2").get_data_type() == xlnt::cell::type::numeric);
TS_ASSERT(ws.get_cell("A2").get_value<int>() == 12345); TS_ASSERT(ws.get_cell("A2").get_value<int>() == 12345);
TS_ASSERT(!ws.get_cell("A2").has_formula()); TS_ASSERT(!ws.get_cell("A2").has_formula());

View File

@ -86,7 +86,7 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml)
} }
} }
auto &shared_strings = sheet_.get_parent().get_shared_strings(); auto &shared_strings = sheet_.get_workbook().get_shared_strings();
for (auto row_node : sheet_data_node.get_children()) for (auto row_node : sheet_data_node.get_children())
{ {
@ -158,7 +158,7 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml)
auto cell = sheet_.get_cell(address); auto cell = sheet_.get_cell(address);
if (has_formula && !has_shared_formula && !sheet_.get_parent().get_data_only()) if (has_formula && !has_shared_formula && !sheet_.get_workbook().get_data_only())
{ {
std::string formula = cell_node.get_child("f").get_text(); std::string formula = cell_node.get_child("f").get_text();
cell.set_formula(formula); cell.set_formula(formula);
@ -365,7 +365,7 @@ xml_document worksheet_serializer::write_worksheet() const
std::unordered_map<std::string, std::string> hyperlink_references; std::unordered_map<std::string, std::string> hyperlink_references;
auto sheet_data_node = root_node.add_child("sheetData"); auto sheet_data_node = root_node.add_child("sheetData");
const auto &shared_strings = sheet_.get_parent().get_shared_strings(); const auto &shared_strings = sheet_.get_workbook().get_shared_strings();
for (auto row : sheet_.rows()) for (auto row : sheet_.rows())
{ {

View File

@ -13,7 +13,7 @@ public:
{ {
xlnt::workbook wb; xlnt::workbook wb;
xlnt::worksheet ws(wb); xlnt::worksheet ws(wb);
TS_ASSERT(ws.get_parent() == wb); TS_ASSERT(ws.get_workbook() == wb);
} }
void test_get_cell() void test_get_cell()

View File

@ -71,7 +71,7 @@ bool worksheet::has_frozen_panes() const
std::string worksheet::unique_sheet_name(const std::string &value) const std::string worksheet::unique_sheet_name(const std::string &value) const
{ {
auto names = get_parent().get_sheet_names(); auto names = get_workbook().get_sheet_names();
auto match = std::find(names.begin(), names.end(), value); auto match = std::find(names.begin(), names.end(), value);
std::size_t append = 0; std::size_t append = 0;
while (match != names.end()) while (match != names.end())
@ -164,11 +164,16 @@ std::string worksheet::to_string() const
return "<Worksheet \"" + d_->title_ + "\">"; return "<Worksheet \"" + d_->title_ + "\">";
} }
workbook &worksheet::get_parent() const workbook &worksheet::get_workbook()
{ {
return *d_->parent_; return *d_->parent_;
} }
const workbook &worksheet::get_workbook() const
{
return *d_->parent_;
}
void worksheet::garbage_collect() void worksheet::garbage_collect()
{ {
auto cell_map_iter = d_->cell_map_.begin(); auto cell_map_iter = d_->cell_map_.begin();
@ -313,7 +318,7 @@ bool worksheet::has_row_properties(row_t row) const
range worksheet::get_named_range(const std::string &name) range worksheet::get_named_range(const std::string &name)
{ {
if (!get_parent().has_named_range(name)) if (!get_workbook().has_named_range(name))
{ {
throw key_error(); throw key_error();
} }

View File

@ -52,6 +52,8 @@ public:
xlnt::xml_document expected_xml; xlnt::xml_document expected_xml;
expected_xml.from_string(expected_contents); expected_xml.from_string(expected_contents);
auto observed_string = observed.to_string();
return compare_xml(expected_xml.get_root(), observed.get_root()); return compare_xml(expected_xml.get_root(), observed.get_root());
} }