implement row and column sizing

This commit is contained in:
Thomas Fussell 2015-10-28 15:08:54 -04:00
parent 0efb3d2f97
commit 3176ee828c
20 changed files with 296 additions and 102 deletions

View File

@ -56,6 +56,7 @@ public:
const std::vector<fill> &get_fills() const { return fills_; }
const std::vector<font> &get_fonts() const { return fonts_; }
const std::vector<number_format> &get_number_formats() const { return number_formats_; }
const std::vector<std::string> &get_colors() const { return colors_; }
private:
style read_style(pugi::xml_node stylesheet_node, pugi::xml_node xf_node);
@ -64,8 +65,8 @@ private:
void read_fills(pugi::xml_node fills_node);
void read_fonts(pugi::xml_node fonts_node);
void read_number_formats(pugi::xml_node num_fmt_node);
void read_colors(pugi::xml_node colors_node);
void read_color_index();
void read_dxfs();
void read_named_styles(pugi::xml_node named_styles_node);
void read_style_names();
@ -77,6 +78,7 @@ private:
std::vector<style> styles_;
std::vector<std::string> colors_;
std::vector<border> borders_;
std::vector<fill> fills_;
std::vector<font> fonts_;

View File

@ -100,8 +100,9 @@ public:
std::size_t hash() const
{
std::size_t seed = wrap_text_;
seed = seed << 1 & shrink_to_fit_;
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_);

View File

@ -44,23 +44,23 @@ class border
public:
static border default_border();
bool start_assigned;
bool start_assigned = false;
side start;
bool end_assigned;
bool end_assigned = false;
side end;
bool left_assigned;
bool left_assigned = false;
side left;
bool right_assigned;
bool right_assigned = false;
side right;
bool top_assigned;
bool top_assigned = false;
side top;
bool bottom_assigned;
bool bottom_assigned = false;
side bottom;
bool diagonal_assigned;
bool diagonal_assigned = false;
side diagonal;
bool vertical_assigned;
bool vertical_assigned = false;
side vertical;
bool horizontal_assigned;
bool horizontal_assigned = false;
side horizontal;
bool outline = false;
@ -78,14 +78,23 @@ public:
{
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;

View File

@ -32,7 +32,8 @@ public:
{
indexed,
theme,
auto_
auto_,
rgb
};
static const color black;
@ -52,6 +53,10 @@ public:
{
}
color(type t, const std::string &v) : type_(t), rgb_string_(v)
{
}
bool operator==(const color &other) const
{
if(type_ != other.type_) return false;
@ -111,9 +116,20 @@ public:
return index_;
}
std::string get_rgb_string() const
{
if(type_ != type::rgb)
{
throw std::runtime_error("not theme color");
}
return rgb_string_;
}
private:
type type_ = type::indexed;
int index_ = 0;
std::string rgb_string_;
};
} // namespace xlnt

View File

@ -218,6 +218,8 @@ public:
case color::type::theme:
hash_combine(seed, static_cast<std::size_t>(foreground_color_.get_theme()));
break;
case color::type::rgb:
break;
}
}
@ -238,6 +240,8 @@ public:
case color::type::theme:
hash_combine(seed, static_cast<std::size_t>(background_color_.get_theme()));
break;
case color::type::rgb:
break;
}
}
}

View File

@ -35,7 +35,7 @@ class style;
class font
{
public:
enum class underline
enum class underline_style
{
none,
double_,
@ -47,6 +47,16 @@ public:
void set_bold(bool bold) { bold_ = bold; }
bool is_bold() const { return bold_; }
void set_italic(bool italic) { italic_ = italic; }
bool is_italic() const { return italic_; }
void set_strikethrough(bool strikethrough) { strikethrough_ = strikethrough; }
bool is_strikethrough() const { return strikethrough_; }
void set_underline(underline_style new_underline) { underline_ = new_underline; }
bool is_underline() const { return underline_ != underline_style::none; }
underline_style get_underline() const { return underline_; }
void set_size(int size) { size_ = size; }
int get_size() const { return size_; }
@ -99,7 +109,7 @@ private:
bool italic_ = false;
bool superscript_ = false;
bool subscript_ = false;
underline underline_ = underline::none;
underline_style underline_ = underline_style::none;
bool strikethrough_ = false;
color color_;
bool has_family_ = false;

View File

@ -62,11 +62,15 @@ public:
{
std::size_t seed = 0;
hash_combine(seed, style_assigned_);
if(style_assigned_)
{
hash_combine(seed, static_cast<std::size_t>(style_));
}
hash_combine(seed, color_assigned_);
if(color_assigned_)
{
hash_combine(seed, static_cast<std::size_t>(color_type_));

View File

@ -210,11 +210,15 @@ public:
std::vector<style> get_styles() const;
std::vector<color> get_colors() const;
std::vector<border> get_borders() const;
std::vector<fill> get_fills() const;
std::vector<font> get_fonts() const;
std::vector<number_format> get_number_formats() const;
std::size_t add_indexed_color(const std::string &rgb);
std::string get_indexed_color(std::size_t color_index) const;
const number_format &get_number_format(std::size_t style_id) const;
std::size_t set_number_format(const number_format &format, std::size_t style_id);
const font &get_font(std::size_t style_id) const;

View File

@ -52,7 +52,6 @@ namespace detail {
class row_properties
{
public:
int row_index;
double height;
bool visible;
int outline_level;
@ -60,6 +59,14 @@ public:
int style_index;
};
class column_properties
{
public:
double width;
std::size_t style;
bool custom;
};
class header
{
public:
@ -176,9 +183,6 @@ public:
const range get_range(const range_reference &reference) const;
range get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row);
const range get_squared_range(column_t min_col, row_t min_row, column_t max_col, row_t max_row) const;
row_properties &get_row_properties(row_t row);
const row_properties &get_row_properties(row_t row) const;
bool has_row_properties(row_t row) const;
range rows() const;
range rows(const std::string &range_string) const;
range rows(int row_offset, int column_offset) const;
@ -186,12 +190,21 @@ public:
range columns() const;
std::list<cell> get_cell_collection();
// properties
column_properties &get_column_properties(column_t column);
const column_properties &get_column_properties(column_t column) const;
bool has_column_properties(column_t column) const;
void add_column_properties(column_t column, const column_properties &props);
row_properties &get_row_properties(row_t row);
const row_properties &get_row_properties(row_t row) const;
bool has_row_properties(row_t row) const;
void add_row_properties(row_t row, const row_properties &props);
// positioning
cell_reference get_point_pos(int left, int top) const;
cell_reference get_point_pos(const std::pair<int, int> &point) const;
const std::unordered_map<column_t, double> &get_column_dimensions() const;
const std::unordered_map<row_t, double> &get_row_dimensions() const;
std::string unique_sheet_name(const std::string &value) const;
// named range

View File

@ -1219,15 +1219,14 @@ std::pair<int, int> cell::get_anchor() const
auto points_to_pixels = [](double value, double dpi) { return (int)std::ceil(value * dpi / 72); };
auto left_columns = d_->column_ - 1;
auto &column_dimensions = get_parent().get_column_dimensions();
int left_anchor = 0;
auto default_width = points_to_pixels(DefaultColumnWidth, 96.0);
for(column_t column_index = 1; column_index <= left_columns; column_index++)
{
if(column_dimensions.find(column_index) != column_dimensions.end())
if(get_parent().has_column_properties(column_index))
{
auto cdw = column_dimensions.at(column_index);
auto cdw = get_parent().get_column_properties(column_index).width;
if(cdw > 0)
{
@ -1240,15 +1239,14 @@ std::pair<int, int> cell::get_anchor() const
}
auto top_rows = d_->row_ - 1;
auto &row_dimensions = get_parent().get_row_dimensions();
int top_anchor = 0;
auto default_height = points_to_pixels(DefaultRowHeight, 96.0);
for(int row_index = 1; row_index <= (int)top_rows; row_index++)
{
if(row_dimensions.find(static_cast<row_t>(row_index)) != row_dimensions.end())
if(get_parent().has_row_properties(row_index))
{
auto rdh = row_dimensions.at(static_cast<row_t>(row_index));
auto rdh = get_parent().get_row_properties(row_index).height;
if(rdh > 0)
{

View File

@ -19,6 +19,7 @@ struct workbook_impl
guess_types_(other.guess_types_),
data_only_(other.data_only_),
styles_(other.styles_),
colors_(other.colors_),
borders_(other.borders_),
fills_(other.fills_),
fonts_(other.fonts_),
@ -43,6 +44,7 @@ struct workbook_impl
fills_ = other.fills_;
fonts_ = other.fonts_;
number_formats_ = other.number_formats_;
colors_ = other.colors_;
return *this;
}
@ -61,6 +63,7 @@ struct workbook_impl
std::size_t next_custom_format_id_;
std::vector<color> colors_;
std::vector<border> borders_;
std::vector<fill> fills_;
std::vector<font> fonts_;

View File

@ -31,6 +31,8 @@ struct worksheet_impl
void operator=(const worksheet_impl &other)
{
parent_ = other.parent_;
column_properties_ = other.column_properties_;
row_properties_ = other.row_properties_;
title_ = other.title_;
freeze_panes_ = other.freeze_panes_;
cell_map_ = other.cell_map_;
@ -52,6 +54,7 @@ struct worksheet_impl
}
workbook *parent_;
std::unordered_map<column_t, column_properties> column_properties_;
std::unordered_map<row_t, row_properties> row_properties_;
std::string title_;
cell_reference freeze_panes_;
@ -64,8 +67,6 @@ struct worksheet_impl
std::unordered_map<std::string, named_range> named_ranges_;
std::size_t comment_count_;
header_footer header_footer_;
std::unordered_map<column_t, double> column_dimensions_;
std::unordered_map<row_t, double> row_dimensions_;
};
} // namespace detail

View File

@ -92,6 +92,11 @@ xlnt::workbook load_workbook(xlnt::zip_file &archive, bool guess_types, bool dat
wb.add_number_format(number_format_);
}
for(auto &color_rgb : style_reader_.get_colors())
{
wb.add_color(xlnt::color(xlnt::color::type::rgb, color_rgb));
}
for(const auto &style : style_reader_.get_styles())
{
wb.add_style(style);

View File

@ -30,7 +30,7 @@ alignment read_alignment(pugi::xml_node node)
{
alignment align;
align.set_wrap_text(node.attribute("wrapText").as_int() != 0);
align.set_wrap_text(node.attribute("wrapText").as_bool());
bool has_vertical = node.attribute("vertical") != nullptr;
std::string vertical = has_vertical ? node.attribute("vertical").as_string() : "";
@ -180,7 +180,8 @@ void style_reader::read_styles(zip_file &archive)
styles_.back().id_ = styles_.size() - 1;
}
read_color_index();
read_colors(stylesheet_node.child("colors"));
read_dxfs();
read_cell_styles();
read_named_styles(root.child("namedStyles"));
@ -203,11 +204,6 @@ void style_reader::read_number_formats(pugi::xml_node num_fmts_node)
}
}
void style_reader::read_color_index()
{
}
void style_reader::read_dxfs()
{
@ -246,10 +242,40 @@ void style_reader::read_fonts(pugi::xml_node fonts_node)
new_font.set_bold(font_node.child("b").attribute("val").as_bool());
}
if(font_node.child("strike") != nullptr)
{
new_font.set_strikethrough(font_node.child("strike").attribute("val").as_bool());
}
if(font_node.child("i") != nullptr)
{
new_font.set_italic(font_node.child("i").attribute("val").as_bool());
}
if(font_node.child("u") != nullptr)
{
std::string underline_string = font_node.child("u").attribute("val").as_string();
if(underline_string == "single")
{
new_font.set_underline(font::underline_style::single);
}
}
fonts_.push_back(new_font);
}
}
void style_reader::read_colors(pugi::xml_node colors_node)
{
auto indexed_colors_node = colors_node.child("indexedColors");
for(auto rgb_color_node : indexed_colors_node.children("rgbColor"))
{
colors_.push_back(rgb_color_node.attribute("rgb").as_string());
}
}
void style_reader::read_fills(pugi::xml_node fills_node)
{
auto pattern_fill_type_from_string = [](const std::string &fill_type)

View File

@ -88,20 +88,24 @@ style &style::operator=(const style &other)
std::size_t style::hash() const
{
std::size_t seed = 0;
if(alignment_apply_) hash_combine(seed, alignment_apply_);
hash_combine(seed, alignment_.hash());
hash_combine(seed, alignment_apply_);
hash_combine(seed, alignment_apply_ ? alignment_.hash() : 0);
hash_combine(seed, border_apply_);
hash_combine(seed, border_id_);
hash_combine(seed, border_apply_ ? border_id_ : 0);
hash_combine(seed, font_apply_);
hash_combine(seed, font_id_);
hash_combine(seed, font_apply_ ? font_id_ : 0);
hash_combine(seed, fill_apply_);
hash_combine(seed, fill_id_);
hash_combine(seed, fill_apply_ ? fill_id_ : 0);
hash_combine(seed, number_format_apply_);
hash_combine(seed, number_format_id_);
hash_combine(seed, number_format_apply_ ? number_format_id_ : 0);
hash_combine(seed, protection_apply_);
if(protection_apply_) hash_combine(seed, get_protection().hash());
// hash_combine(seed, pivot_button_);
// hash_combine(seed, quote_prefix_);
hash_combine(seed, protection_apply_ ? get_protection().hash() : 0);
return seed;
}

View File

@ -597,17 +597,10 @@ std::vector<named_range> workbook::get_named_ranges() const
std::size_t workbook::add_style(const xlnt::style &style_)
{
for(std::size_t i = 0; i < d_->styles_.size(); i++)
{
if(d_->styles_[i] == style_)
{
return i;
}
}
d_->styles_.push_back(style_);
d_->styles_.back().id_ = d_->styles_.size() - 1;
return d_->styles_.size() - 1;
return d_->styles_.back().id_;
}
const number_format &workbook::get_number_format(std::size_t style_id) const
@ -829,4 +822,19 @@ std::vector<fill> workbook::get_fills() const
return d_->fills_;
}
void workbook::add_color(const color &rgb)
{
d_->colors_.push_back(rgb);
}
std::string workbook::get_indexed_color(std::size_t color_index) const
{
return d_->colors_.at(color_index).get_rgb_string();
}
std::vector<color> workbook::get_colors() const
{
return d_->colors_;
}
} // namespace xlnt

View File

@ -196,16 +196,6 @@ void worksheet::unfreeze_panes()
d_->freeze_panes_ = cell_reference("A1");
}
const std::unordered_map<column_t, double> &worksheet::get_column_dimensions() const
{
return d_->column_dimensions_;
}
const std::unordered_map<row_t, double> &worksheet::get_row_dimensions() const
{
return d_->row_dimensions_;
}
cell worksheet::get_cell(const cell_reference &reference)
{
if(d_->cell_map_.find(reference.get_row()) == d_->cell_map_.end())
@ -228,11 +218,6 @@ const cell worksheet::get_cell(const cell_reference &reference) const
return cell(&d_->cell_map_.at(reference.get_row()).at(reference.get_column_index()));
}
row_properties &worksheet::get_row_properties(row_t row)
{
return d_->row_properties_[row];
}
bool worksheet::has_row_properties(row_t row) const
{
return d_->row_properties_.find(row) != d_->row_properties_.end();
@ -663,9 +648,9 @@ cell_reference worksheet::get_point_pos(int left, int top) const
{
current_column++;
if(d_->column_dimensions_.find(current_column) != d_->column_dimensions_.end())
if(has_column_properties(current_column))
{
auto cdw = d_->column_dimensions_.at(current_column);
auto cdw = get_column_properties(current_column).width;
if(cdw >= 0)
{
@ -681,9 +666,9 @@ cell_reference worksheet::get_point_pos(int left, int top) const
{
current_row++;
if(d_->row_dimensions_.find(current_row) != d_->row_dimensions_.end())
if(has_row_properties(current_row))
{
auto cdh = d_->column_dimensions_.at(current_row);
auto cdh = get_row_properties(current_row).height;
if(cdh >= 0)
{
@ -708,4 +693,34 @@ void worksheet::set_sheet_state(page_setup::sheet_state state)
get_page_setup().set_sheet_state(state);
}
void worksheet::add_column_properties(column_t column, const xlnt::column_properties &props)
{
d_->column_properties_[column] = props;
}
bool worksheet::has_column_properties(column_t column) const
{
return d_->column_properties_.find(column) != d_->column_properties_.end();
}
column_properties &worksheet::get_column_properties(column_t column)
{
return d_->column_properties_[column];
}
const column_properties &worksheet::get_column_properties(column_t column) const
{
return d_->column_properties_.at(column);
}
row_properties &worksheet::get_row_properties(row_t row)
{
return d_->row_properties_[row];
}
const row_properties &worksheet::get_row_properties(row_t row) const
{
return d_->row_properties_.at(row);
}
} // namespace xlnt

View File

@ -46,7 +46,13 @@ void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, co
for(auto row_node : sheet_data_node.children("row"))
{
int row_index = row_node.attribute("r").as_int();
auto row_index = static_cast<row_t>(row_node.attribute("r").as_uint());
if(row_node.attribute("ht") != nullptr)
{
ws.get_row_properties(row_index).height = row_node.attribute("ht").as_double();
}
std::string span_string = row_node.attribute("spans").as_string();
auto colon_index = span_string.find(':');
@ -130,6 +136,29 @@ void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, co
}
}
auto cols_node = root_node.child("cols");
for(auto col_node : cols_node.children("col"))
{
column_t min = col_node.attribute("min").as_uint();
column_t max = col_node.attribute("max").as_uint();
double width = col_node.attribute("width").as_double();
std::size_t column_style = col_node.attribute("style").as_ullong();
bool custom = col_node.attribute("customWidth").as_bool();
for(auto column = min; column <= max; column++)
{
if(!ws.has_column_properties(column))
{
ws.add_column_properties(column, column_properties());
}
ws.get_column_properties(min).width = width;
ws.get_column_properties(min).style = column_style;
ws.get_column_properties(min).custom = custom;
}
}
auto auto_filter_node = root_node.child("autoFilter");
if(auto_filter_node != nullptr)

View File

@ -53,6 +53,38 @@ std::string style_writer::write_table() const
{
auto font_node = fonts_node.append_child("font");
if(f.is_bold())
{
auto bold_node = font_node.append_child("b");
bold_node.append_attribute("val").set_value(1);
}
if(f.is_italic())
{
auto bold_node = font_node.append_child("i");
bold_node.append_attribute("val").set_value(1);
}
if(f.is_underline())
{
auto bold_node = font_node.append_child("u");
switch(f.get_underline())
{
case font::underline_style::single:
bold_node.append_attribute("val").set_value("single");
break;
default:
break;
}
}
if(f.is_strikethrough())
{
auto bold_node = font_node.append_child("strike");
bold_node.append_attribute("val").set_value(1);
}
auto size_node = font_node.append_child("sz");
size_node.append_attribute("val").set_value(f.get_size());
@ -81,12 +113,6 @@ std::string style_writer::write_table() const
auto scheme_node = font_node.append_child("scheme");
scheme_node.append_attribute("val").set_value("minor");
}
if(f.is_bold())
{
auto bold_node = font_node.append_child("b");
bold_node.append_attribute("val").set_value(1);
}
}
auto fills_node = style_sheet_node.append_child("fills");
@ -343,27 +369,9 @@ std::string style_writer::write_table() const
auto colors_node = style_sheet_node.append_child("colors");
auto indexed_colors_node = colors_node.append_child("indexedColors");
const std::vector<std::string> colors =
for(auto &c : wb_.get_colors())
{
"ff000000",
"ffffffff",
"ffff0000",
"ff00ff00",
"ff0000ff",
"ffffff00",
"ffff00ff",
"ff00ffff",
"ff000000",
"ffaaaaaa",
"ffbdc0bf",
"ffdbdbdb",
"ffbdc0bf",
"ffdbdbdb"
};
for(auto &color : colors)
{
indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(color.c_str());
indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(c.get_rgb_string().c_str());
}
auto ext_list_node = style_sheet_node.append_child("extLst");

View File

@ -84,6 +84,7 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
}
auto selection_node = sheet_view_node.append_child("selection");
if(ws.has_frozen_panes())
{
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
@ -99,6 +100,7 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
selection_node.append_attribute("pane").set_value("topRight");
}
}
std::string active_cell = "A1";
selection_node.append_attribute("activeCell").set_value(active_cell.c_str());
selection_node.append_attribute("sqref").set_value(active_cell.c_str());
@ -107,6 +109,35 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
sheet_format_pr_node.append_attribute("baseColWidth").set_value(10);
sheet_format_pr_node.append_attribute("defaultRowHeight").set_value(15);
bool has_column_properties = false;
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
{
if(ws.has_column_properties(column))
{
has_column_properties = true;
break;
}
}
if(has_column_properties)
{
auto cols_node = root_node.append_child("cols");
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
{
const auto &props = ws.get_column_properties(column);
auto col_node = cols_node.append_child("col");
col_node.append_attribute("min").set_value(column);
col_node.append_attribute("max").set_value(column);
col_node.append_attribute("width").set_value(props.width);
col_node.append_attribute("style").set_value(static_cast<unsigned long long>(props.style));
col_node.append_attribute("customWidth").set_value(props.custom ? 1 : 0);
}
}
std::unordered_map<std::string, std::string> hyperlink_references;
auto sheet_data_node = root_node.append_child("sheetData");
@ -134,13 +165,15 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
}
auto row_node = sheet_data_node.append_child("row");
row_node.append_attribute("r").set_value(row.front().get_row());
row_node.append_attribute("r").set_value(row.front().get_row());
row_node.append_attribute("spans").set_value((std::to_string(min) + ":" + std::to_string(max)).c_str());
if(ws.has_row_properties(row.front().get_row()))
{
row_node.append_attribute("customHeight").set_value(1);
auto height = ws.get_row_properties(row.front().get_row()).height;
if(height == std::floor(height))
{
row_node.append_attribute("ht").set_value((std::to_string((int)height) + ".0").c_str());
@ -150,6 +183,7 @@ std::string write_worksheet(worksheet ws, const std::vector<std::string> &string
row_node.append_attribute("ht").set_value(height);
}
}
//row_node.append_attribute("x14ac:dyDescent").set_value(0.25);
for(auto cell : row)