Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update definedNames #686

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
33 changes: 33 additions & 0 deletions include/xlnt/workbook/workbook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct stylesheet;
struct workbook_impl;
class xlsx_consumer;
class xlsx_producer;
struct defined_name;

} // namespace detail

Expand Down Expand Up @@ -751,6 +752,38 @@ class XLNT_API workbook
/// </summary>
bool known_fonts_enabled() const;

// Defined Names

/// <summary>
/// Add a defined name to a sheet
/// </summary
void add_defined_name(detail::defined_name name);

/// <summary>
/// Returns a copy of workbook defined names
/// </summary>
std::vector<detail::defined_name> get_defined_names() const;

/// <summary>
/// Returns a reference to a single defined name
/// </summary>
detail::defined_name &get_defined_name(const std::size_t index);

/// <summary>
/// Returns a reference to a single defined name. Finds the first name that matches, there may be multiple with the same name
/// </summary>
detail::defined_name &get_defined_name(const std::string &name);

/// <summary>
/// Removes the defined name at the given index
/// </summary>
void remove_defined_name(const std::size_t index);

/// <summary>
/// Removes the defined name that first matches the passed name.
/// </summary>
void remove_defined_name(const std::string &name);

// Manifest

/// <summary>
Expand Down
34 changes: 33 additions & 1 deletion include/xlnt/worksheet/worksheet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace detail {

class xlsx_consumer;
class xlsx_producer;

struct defined_name;
struct worksheet_impl;

} // namespace detail
Expand Down Expand Up @@ -729,6 +729,38 @@ class XLNT_API worksheet
/// </summary>
cell_reference active_cell() const;

// Defined Names

/// <summary>
/// Add a defined name to a sheet
/// </summary
void add_defined_name(detail::defined_name name);

/// <summary>
/// Returns a copy of workbook defined names
/// </summary>
std::vector<detail::defined_name> get_defined_names() const;

/// <summary>
/// Returns a reference to a single defined name
/// </summary>
detail::defined_name &get_defined_name(const std::size_t index);

/// <summary>
/// Returns a reference to a single defined name. Finds the first name that matches, there may be multiple with the same name
/// </summary>
detail::defined_name &get_defined_name(const std::string &name);

/// <summary>
/// Removes the defined name at the given index
/// </summary>
void remove_defined_name(const std::size_t index);

/// <summary>
/// Removes the defined name that first matches the passed name.
/// </summary>
void remove_defined_name(const std::string &name);

// page breaks

/// <summary>
Expand Down
13 changes: 12 additions & 1 deletion source/detail/implementations/workbook_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#include <detail/implementations/stylesheet.hpp>
#include <detail/implementations/worksheet_impl.hpp>
#include <detail/serialization/defined_name.hpp>
#include <xlnt/packaging/ext_list.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/datetime.hpp>
Expand Down Expand Up @@ -88,11 +89,20 @@ struct workbook_impl
extended_properties_ = other.extended_properties_;
custom_properties_ = other.custom_properties_;

defined_names_ = other.defined_names_;

return *this;
}

bool operator==(const workbook_impl &other)
bool operator==(const workbook_impl &other) const
{
if (defined_names_.size() != other.defined_names_.size()) return false;

for (std::size_t i = 0; i < defined_names_.size(); i++)
{
if (defined_names_[i] != other.defined_names_[i]) return false;
}

return active_sheet_index_ == other.active_sheet_index_
&& worksheets_ == other.worksheets_
&& shared_strings_ids_ == other.shared_strings_ids_
Expand Down Expand Up @@ -168,6 +178,7 @@ struct workbook_impl
optional<std::string> abs_path_;
optional<std::size_t> arch_id_flags_;
optional<ext_list> extensions_;
std::vector<defined_name> defined_names_;
};

} // namespace detail
Expand Down
15 changes: 14 additions & 1 deletion source/detail/implementations/worksheet_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <xlnt/worksheet/print_options.hpp>
#include <xlnt/worksheet/sheet_pr.hpp>
#include <detail/implementations/cell_impl.hpp>
#include <detail/serialization/defined_name.hpp>

namespace xlnt {

Expand Down Expand Up @@ -88,6 +89,8 @@ struct worksheet_impl
extension_list_ = other.extension_list_;
sheet_properties_ = other.sheet_properties_;
print_options_ = other.print_options_;
defined_names_ = other.defined_names_;


for (auto &cell : cell_map_)
{
Expand All @@ -97,8 +100,15 @@ struct worksheet_impl

workbook *parent_;

bool operator==(const worksheet_impl& rhs) const
bool operator==(const worksheet_impl &rhs) const
{
if (defined_names_.size() != rhs.defined_names_.size()) return false;

for (std::size_t i = 0; i < defined_names_.size(); i++)
{
if (defined_names_[i] != rhs.defined_names_[i]) return false;
}

return id_ == rhs.id_
&& title_ == rhs.title_
&& format_properties_ == rhs.format_properties_
Expand All @@ -122,6 +132,7 @@ struct worksheet_impl
&& print_options_ == rhs.print_options_
&& sheet_properties_ == rhs.sheet_properties_
&& extension_list_ == rhs.extension_list_;

}

std::size_t id_;
Expand Down Expand Up @@ -160,6 +171,8 @@ struct worksheet_impl

std::string drawing_rel_id_;
optional<drawing::spreadsheet_drawing> drawing_;

std::vector<defined_name> defined_names_;
};

} // namespace detail
Expand Down
61 changes: 57 additions & 4 deletions source/detail/serialization/defined_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,63 @@ namespace detail {

struct defined_name
{
std::string name;
std::size_t sheet_id;
bool hidden;
std::string value;

defined_name &operator=(const defined_name &other)
{
name = other.name;
comment = other.comment;
custom_menu = other.custom_menu;
description = other.description;
help = other.help;

status_bar = other.status_bar;
sheet_id = other.sheet_id;
hidden = other.hidden;
function = other.function;
function_group_id = other.function_group_id;

shortcut_key = other.shortcut_key;
value = other.value;

return *this;
}

bool operator==(const defined_name &other) const
{
return name == other.name
&& comment == other.comment
&& custom_menu == other.custom_menu
&& description == other.description
&& help == other.help
&& status_bar == other.status_bar
&& sheet_id == other.sheet_id
&& hidden == other.hidden
&& function == other.function
&& function_group_id == other.function_group_id
&& shortcut_key == other.shortcut_key
&& value == other.value;
}

bool operator!=(const defined_name &other) const
{
return !(*this == other);
}

// Implements (most of) CT_RevisionDefinedName, there's several "old" members in the spec but they're also ignored in other librarie
std::string name; // A string representing the name for this defined name.
optional<std::string> comment; // A string representing a comment about the defined name.
optional<std::string> custom_menu; // A string representing the new custom menu text
optional<std::string> description; // A string representing the new description text for the defined name.
optional<std::string> help; // A string representing the new help topic text.
optional<std::string> status_bar; // A string representing the new status bar text.
optional<std::size_t> sheet_id; // An integer representing the id of the sheet to which this defined name belongs. This shall be used local defined names only. 0 indexed indexed.
optional<bool> hidden; // A Boolean value indicating whether the named range is now hidden.
optional<bool> function; // A Boolean value indicating that the defined name refers to a function. True if the defined name is a function, false otherwise.
optional<std::size_t> function_group_id;// Represents the new function group id.
optional<std::string> shortcut_key; // Represents the new keyboard shortcut. This is unsigned byte in the spec, but openpyxl uses string so let's try that
std::string value; // The actual value of the name, ie "='Sheet1'!A1"


};

} // namespace detail
Expand Down
81 changes: 75 additions & 6 deletions source/detail/serialization/xlsx_consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id)
expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet
skip_attributes({qn("mc", "Ignorable")});

read_defined_names(ws, defined_names_);
read_defined_names(ws, ws.d_->defined_names_);

while (in_element(qn("spreadsheetml", "worksheet")))
{
Expand Down Expand Up @@ -2082,16 +2082,61 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_

defined_name name;
name.name = parser().attribute("name");
name.sheet_id = parser().attribute<std::size_t>("localSheetId");
name.hidden = false;

if (parser().attribute_present("comment"))
{
name.comment = parser().attribute<std::string>("comment");
}

if (parser().attribute_present("customMenu"))
{
name.custom_menu = parser().attribute<std::string>("customMenu");
}

if (parser().attribute_present("description"))
{
name.description = parser().attribute<std::string>("description");
}

if (parser().attribute_present("help"))
{
name.help = parser().attribute<std::string>("help");
}

if (parser().attribute_present("statusBar"))
{
name.status_bar = parser().attribute<std::string>("statusBar");
}

if (parser().attribute_present("localSheetId"))
{
name.sheet_id = parser().attribute<std::size_t>("localSheetId");
}

if (parser().attribute_present("hidden"))
{
name.hidden = is_true(parser().attribute("hidden"));
}

if (parser().attribute_present("function"))
{
name.function = is_true(parser().attribute("function"));
}

if (parser().attribute_present("functionGroupId"))
{
name.function_group_id = parser().attribute<std::size_t>("functionGroupId");
}

if (parser().attribute_present("shortcutKey"))
{
name.shortcut_key = parser().attribute<std::string>("shortcutKey");
}

parser().attribute_map(); // skip remaining attributes
name.value = read_text();
defined_names_.push_back(name);
target_.d_->defined_names_.push_back(name);

expect_end_element(qn("spreadsheetml", "definedName"));
}
}
Expand Down Expand Up @@ -2195,6 +2240,7 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
}
}

std::vector<defined_name> workbook_names;
for (auto worksheet_rel : manifest().relationships(workbook_path, relationship_type::worksheet))
{
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
Expand All @@ -2203,7 +2249,7 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
return p.second == worksheet_rel.id();
})->first;

auto id = sheet_title_id_map_[title];
auto id = sheet_title_id_map_[title]; // 1-indexed
auto index = sheet_title_index_map_[title];

auto insertion_iter = target_.d_->worksheets_.begin();
Expand All @@ -2215,11 +2261,34 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_

current_worksheet_ = &*target_.d_->worksheets_.emplace(insertion_iter, &target_, id, title);

// If there's any defined names that are worksheet specific, move them here.
for (std::size_t i = 0; i < target_.d_->defined_names_.size(); i++)
{
const auto &name = target_.d_->defined_names_[i];
if (name.sheet_id.is_set())
{
const auto target_id = name.sheet_id.get();
if (target_id == index)
{
// It's a match, remove it from the workbook and add it to the sheet
current_worksheet_->defined_names_.push_back(name);
}
}
else
{
// Name is global and belongs to the workbook, if i'ts not already added
if (std::find(workbook_names.begin(), workbook_names.end(), name) == workbook_names.end())
workbook_names.push_back(name);
}
}

if (!streaming_)
{
read_part({workbook_rel, worksheet_rel});
}
}
// Update the workbook with the new defined names
target_.d_->defined_names_ = workbook_names;
}

// Write Workbook Relationship Target Parts
Expand Down
Loading