Skip to content

Commit

Permalink
fix empty row height/cell width, #235
Browse files Browse the repository at this point in the history
  • Loading branch information
tfussell committed Oct 30, 2017
1 parent dc4befd commit 470c655
Show file tree
Hide file tree
Showing 6 changed files with 309 additions and 155 deletions.
20 changes: 20 additions & 0 deletions include/xlnt/worksheet/worksheet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,21 @@ class XLNT_API worksheet
/// </summary>
row_t lowest_row() const;

/// <summary>
/// Returns the row of the first non-empty cell or lowest row with properties in the worksheet.
/// </summary>
row_t lowest_row_or_props() const;

/// <summary>
/// Returns the row of the last non-empty cell in the worksheet.
/// </summary>
row_t highest_row() const;

/// <summary>
/// Returns the row of the last non-empty cell or highest row with properties in the worksheet.
/// </summary>
row_t highest_row_or_props() const;

/// <summary>
/// Returns the row directly below the last non-empty cell in the worksheet.
/// </summary>
Expand All @@ -385,11 +395,21 @@ class XLNT_API worksheet
/// </summary>
column_t lowest_column() const;

/// <summary>
/// Returns the column of the first non-empty cell or lowest column with properties in the worksheet.
/// </summary>
column_t lowest_column_or_props() const;

/// <summary>
/// Returns the column of the last non-empty cell in the worksheet.
/// </summary>
column_t highest_column() const;

/// <summary>
/// Returns the column of the last non-empty cell or highest column with properties in the worksheet.
/// </summary>
column_t highest_column_or_props() const;

/// <summary>
/// Returns a range_reference pointing to the full range of non-empty cells in the worksheet.
/// </summary>
Expand Down
235 changes: 124 additions & 111 deletions source/detail/serialization/xlsx_producer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2030,8 +2030,9 @@ void xlsx_producer::write_worksheet(const relationship &rel)

write_start_element(xmlns, "dimension");
const auto dimension = ws.calculate_dimension();
write_attribute(
"ref", dimension.is_single_cell() ? dimension.top_left().to_string() : dimension.to_string());
write_attribute("ref", dimension.is_single_cell()
? dimension.top_left().to_string()
: dimension.to_string());
write_end_element(xmlns, "dimension");

if (ws.has_view())
Expand Down Expand Up @@ -2123,7 +2124,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
{
write_start_element(xmlns, "cols");

for (auto column = ws.lowest_column(); column <= ws.highest_column(); column++)
for (auto column = ws.lowest_column_or_props(); column <= ws.highest_column_or_props(); column++)
{
if (!ws.has_column_properties(column)) continue;

Expand Down Expand Up @@ -2172,36 +2173,41 @@ void xlsx_producer::write_worksheet(const relationship &rel)

write_start_element(xmlns, "sheetData");

for (auto row : ws.rows())
for (auto row = ws.lowest_row_or_props(); row <= ws.highest_row_or_props(); ++row)
{
auto min = static_cast<xlnt::row_t>(row.length());
xlnt::row_t max = 0;
auto first_column = constants::max_column();
auto last_column = constants::min_column();
bool any_non_null = false;

for (auto cell : row)
for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
{
min = std::min(min, cell.column().index);
max = std::max(max, cell.column().index);
if (!ws.has_cell(cell_reference(column, row))) continue;

auto cell = ws.cell(cell_reference(column, row));

first_column = std::min(first_column, cell.column());
last_column = std::max(last_column, cell.column());

if (!cell.garbage_collectible())
{
any_non_null = true;
}
}

if (!any_non_null)
{
continue;
}
if (!any_non_null && !ws.has_row_properties(row)) continue;

write_start_element(xmlns, "row");
write_attribute("r", row);

write_attribute("r", row.front().row());
write_attribute("spans", std::to_string(min) + ":" + std::to_string(max));
if (any_non_null)
{
auto span_string = std::to_string(first_column.index) + ":" + std::to_string(last_column.index);
write_attribute("spans", span_string);
}

if (ws.has_row_properties(row.front().row()))
if (ws.has_row_properties(row))
{
const auto &props = ws.row_properties(row.front().row());
const auto &props = ws.row_properties(row);

if (props.custom_height)
{
Expand All @@ -2228,130 +2234,137 @@ void xlsx_producer::write_worksheet(const relationship &rel)
}
}

for (auto cell : row) // CT_Cell
if (any_non_null)
{
if (cell.garbage_collectible()) continue;
for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
{
if (!ws.has_cell(cell_reference(column, row))) continue;

// record data about the cell needed later
auto cell = ws.cell(cell_reference(column, row));

if (cell.has_comment())
{
cells_with_comments.push_back(cell.reference());
}
if (cell.garbage_collectible()) continue;

if (cell.has_hyperlink())
{
hyperlink_references[cell.reference().to_string()] = reverse_hyperlink_references[cell.hyperlink()];
}
// record data about the cell needed later

write_start_element(xmlns, "c");
if (cell.has_comment())
{
cells_with_comments.push_back(cell.reference());
}

// begin cell attributes
if (cell.has_hyperlink())
{
hyperlink_references[cell.reference().to_string()] = reverse_hyperlink_references[cell.hyperlink()];
}

write_attribute("r", cell.reference().to_string());
write_start_element(xmlns, "c");

if (cell.has_format())
{
write_attribute("s", cell.format().d_->id);
}
// begin cell attributes

switch (cell.data_type())
{
case cell::type::empty:
break;
write_attribute("r", cell.reference().to_string());

case cell::type::boolean:
write_attribute("t", "b");
break;
if (cell.has_format())
{
write_attribute("s", cell.format().d_->id);
}

case cell::type::date:
write_attribute("t", "d");
break;
switch (cell.data_type())
{
case cell::type::empty:
break;

case cell::type::error:
write_attribute("t", "e");
break;
case cell::type::boolean:
write_attribute("t", "b");
break;

case cell::type::inline_string:
write_attribute("t", "inlineStr");
break;
case cell::type::date:
write_attribute("t", "d");
break;

case cell::type::number:
write_attribute("t", "n");
break;
case cell::type::error:
write_attribute("t", "e");
break;

case cell::type::shared_string:
write_attribute("t", "s");
break;
case cell::type::inline_string:
write_attribute("t", "inlineStr");
break;

case cell::type::formula_string:
write_attribute("t", "str");
break;
}
case cell::type::number:
write_attribute("t", "n");
break;

//write_attribute("cm", "");
//write_attribute("vm", "");
//write_attribute("ph", "");
case cell::type::shared_string:
write_attribute("t", "s");
break;

// begin child elements
case cell::type::formula_string:
write_attribute("t", "str");
break;
}

if (cell.has_formula())
{
write_element(xmlns, "f", cell.formula());
}
//write_attribute("cm", "");
//write_attribute("vm", "");
//write_attribute("ph", "");

switch (cell.data_type())
{
case cell::type::empty:
break;
// begin child elements

case cell::type::boolean:
write_element(xmlns, "v", write_bool(cell.value<bool>()));
break;
if (cell.has_formula())
{
write_element(xmlns, "f", cell.formula());
}

case cell::type::date:
write_element(xmlns, "v", cell.value<std::string>());
break;
switch (cell.data_type())
{
case cell::type::empty:
break;

case cell::type::error:
write_element(xmlns, "v", cell.value<std::string>());
break;
case cell::type::boolean:
write_element(xmlns, "v", write_bool(cell.value<bool>()));
break;

case cell::type::inline_string:
write_start_element(xmlns, "is");
// TODO: make a write_rich_text method and use that here
write_element(xmlns, "t", cell.value<std::string>());
write_end_element(xmlns, "is");
break;
case cell::type::date:
write_element(xmlns, "v", cell.value<std::string>());
break;

case cell::type::number:
write_start_element(xmlns, "v");
case cell::type::error:
write_element(xmlns, "v", cell.value<std::string>());
break;

if (is_integral(cell.value<double>()))
{
write_characters(static_cast<std::int64_t>(cell.value<double>()));
}
else
{
std::stringstream ss;
ss.precision(20);
ss << cell.value<double>();
write_characters(ss.str());
}
case cell::type::inline_string:
write_start_element(xmlns, "is");
// TODO: make a write_rich_text method and use that here
write_element(xmlns, "t", cell.value<std::string>());
write_end_element(xmlns, "is");
break;

write_end_element(xmlns, "v");
break;
case cell::type::number:
write_start_element(xmlns, "v");

case cell::type::shared_string:
write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
break;
if (is_integral(cell.value<double>()))
{
write_characters(static_cast<std::int64_t>(cell.value<double>()));
}
else
{
std::stringstream ss;
ss.precision(20);
ss << cell.value<double>();
write_characters(ss.str());
}

case cell::type::formula_string:
write_element(xmlns, "v", cell.value<std::string>());
break;
}
write_end_element(xmlns, "v");
break;

case cell::type::shared_string:
write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
break;

write_end_element(xmlns, "c");
case cell::type::formula_string:
write_element(xmlns, "v", cell.value<std::string>());
break;
}

write_end_element(xmlns, "c");
}
}

write_end_element(xmlns, "row");
Expand Down
Loading

0 comments on commit 470c655

Please sign in to comment.