Skip to content

Commit 470c655

Browse files
committed
fix empty row height/cell width, #235
1 parent dc4befd commit 470c655

File tree

6 files changed

+309
-155
lines changed

6 files changed

+309
-155
lines changed

Diff for: include/xlnt/worksheet/worksheet.hpp

+20
Original file line numberDiff line numberDiff line change
@@ -370,11 +370,21 @@ class XLNT_API worksheet
370370
/// </summary>
371371
row_t lowest_row() const;
372372

373+
/// <summary>
374+
/// Returns the row of the first non-empty cell or lowest row with properties in the worksheet.
375+
/// </summary>
376+
row_t lowest_row_or_props() const;
377+
373378
/// <summary>
374379
/// Returns the row of the last non-empty cell in the worksheet.
375380
/// </summary>
376381
row_t highest_row() const;
377382

383+
/// <summary>
384+
/// Returns the row of the last non-empty cell or highest row with properties in the worksheet.
385+
/// </summary>
386+
row_t highest_row_or_props() const;
387+
378388
/// <summary>
379389
/// Returns the row directly below the last non-empty cell in the worksheet.
380390
/// </summary>
@@ -385,11 +395,21 @@ class XLNT_API worksheet
385395
/// </summary>
386396
column_t lowest_column() const;
387397

398+
/// <summary>
399+
/// Returns the column of the first non-empty cell or lowest column with properties in the worksheet.
400+
/// </summary>
401+
column_t lowest_column_or_props() const;
402+
388403
/// <summary>
389404
/// Returns the column of the last non-empty cell in the worksheet.
390405
/// </summary>
391406
column_t highest_column() const;
392407

408+
/// <summary>
409+
/// Returns the column of the last non-empty cell or highest column with properties in the worksheet.
410+
/// </summary>
411+
column_t highest_column_or_props() const;
412+
393413
/// <summary>
394414
/// Returns a range_reference pointing to the full range of non-empty cells in the worksheet.
395415
/// </summary>

Diff for: source/detail/serialization/xlsx_producer.cpp

+124-111
Original file line numberDiff line numberDiff line change
@@ -2030,8 +2030,9 @@ void xlsx_producer::write_worksheet(const relationship &rel)
20302030

20312031
write_start_element(xmlns, "dimension");
20322032
const auto dimension = ws.calculate_dimension();
2033-
write_attribute(
2034-
"ref", dimension.is_single_cell() ? dimension.top_left().to_string() : dimension.to_string());
2033+
write_attribute("ref", dimension.is_single_cell()
2034+
? dimension.top_left().to_string()
2035+
: dimension.to_string());
20352036
write_end_element(xmlns, "dimension");
20362037

20372038
if (ws.has_view())
@@ -2123,7 +2124,7 @@ void xlsx_producer::write_worksheet(const relationship &rel)
21232124
{
21242125
write_start_element(xmlns, "cols");
21252126

2126-
for (auto column = ws.lowest_column(); column <= ws.highest_column(); column++)
2127+
for (auto column = ws.lowest_column_or_props(); column <= ws.highest_column_or_props(); column++)
21272128
{
21282129
if (!ws.has_column_properties(column)) continue;
21292130

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

21732174
write_start_element(xmlns, "sheetData");
21742175

2175-
for (auto row : ws.rows())
2176+
for (auto row = ws.lowest_row_or_props(); row <= ws.highest_row_or_props(); ++row)
21762177
{
2177-
auto min = static_cast<xlnt::row_t>(row.length());
2178-
xlnt::row_t max = 0;
2178+
auto first_column = constants::max_column();
2179+
auto last_column = constants::min_column();
21792180
bool any_non_null = false;
21802181

2181-
for (auto cell : row)
2182+
for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
21822183
{
2183-
min = std::min(min, cell.column().index);
2184-
max = std::max(max, cell.column().index);
2184+
if (!ws.has_cell(cell_reference(column, row))) continue;
2185+
2186+
auto cell = ws.cell(cell_reference(column, row));
2187+
2188+
first_column = std::min(first_column, cell.column());
2189+
last_column = std::max(last_column, cell.column());
21852190

21862191
if (!cell.garbage_collectible())
21872192
{
21882193
any_non_null = true;
21892194
}
21902195
}
21912196

2192-
if (!any_non_null)
2193-
{
2194-
continue;
2195-
}
2197+
if (!any_non_null && !ws.has_row_properties(row)) continue;
21962198

21972199
write_start_element(xmlns, "row");
2200+
write_attribute("r", row);
21982201

2199-
write_attribute("r", row.front().row());
2200-
write_attribute("spans", std::to_string(min) + ":" + std::to_string(max));
2202+
if (any_non_null)
2203+
{
2204+
auto span_string = std::to_string(first_column.index) + ":" + std::to_string(last_column.index);
2205+
write_attribute("spans", span_string);
2206+
}
22012207

2202-
if (ws.has_row_properties(row.front().row()))
2208+
if (ws.has_row_properties(row))
22032209
{
2204-
const auto &props = ws.row_properties(row.front().row());
2210+
const auto &props = ws.row_properties(row);
22052211

22062212
if (props.custom_height)
22072213
{
@@ -2228,130 +2234,137 @@ void xlsx_producer::write_worksheet(const relationship &rel)
22282234
}
22292235
}
22302236

2231-
for (auto cell : row) // CT_Cell
2237+
if (any_non_null)
22322238
{
2233-
if (cell.garbage_collectible()) continue;
2239+
for (auto column = dimension.top_left().column(); column <= dimension.bottom_right().column(); ++column)
2240+
{
2241+
if (!ws.has_cell(cell_reference(column, row))) continue;
22342242

2235-
// record data about the cell needed later
2243+
auto cell = ws.cell(cell_reference(column, row));
22362244

2237-
if (cell.has_comment())
2238-
{
2239-
cells_with_comments.push_back(cell.reference());
2240-
}
2245+
if (cell.garbage_collectible()) continue;
22412246

2242-
if (cell.has_hyperlink())
2243-
{
2244-
hyperlink_references[cell.reference().to_string()] = reverse_hyperlink_references[cell.hyperlink()];
2245-
}
2247+
// record data about the cell needed later
22462248

2247-
write_start_element(xmlns, "c");
2249+
if (cell.has_comment())
2250+
{
2251+
cells_with_comments.push_back(cell.reference());
2252+
}
22482253

2249-
// begin cell attributes
2254+
if (cell.has_hyperlink())
2255+
{
2256+
hyperlink_references[cell.reference().to_string()] = reverse_hyperlink_references[cell.hyperlink()];
2257+
}
22502258

2251-
write_attribute("r", cell.reference().to_string());
2259+
write_start_element(xmlns, "c");
22522260

2253-
if (cell.has_format())
2254-
{
2255-
write_attribute("s", cell.format().d_->id);
2256-
}
2261+
// begin cell attributes
22572262

2258-
switch (cell.data_type())
2259-
{
2260-
case cell::type::empty:
2261-
break;
2263+
write_attribute("r", cell.reference().to_string());
22622264

2263-
case cell::type::boolean:
2264-
write_attribute("t", "b");
2265-
break;
2265+
if (cell.has_format())
2266+
{
2267+
write_attribute("s", cell.format().d_->id);
2268+
}
22662269

2267-
case cell::type::date:
2268-
write_attribute("t", "d");
2269-
break;
2270+
switch (cell.data_type())
2271+
{
2272+
case cell::type::empty:
2273+
break;
22702274

2271-
case cell::type::error:
2272-
write_attribute("t", "e");
2273-
break;
2275+
case cell::type::boolean:
2276+
write_attribute("t", "b");
2277+
break;
22742278

2275-
case cell::type::inline_string:
2276-
write_attribute("t", "inlineStr");
2277-
break;
2279+
case cell::type::date:
2280+
write_attribute("t", "d");
2281+
break;
22782282

2279-
case cell::type::number:
2280-
write_attribute("t", "n");
2281-
break;
2283+
case cell::type::error:
2284+
write_attribute("t", "e");
2285+
break;
22822286

2283-
case cell::type::shared_string:
2284-
write_attribute("t", "s");
2285-
break;
2287+
case cell::type::inline_string:
2288+
write_attribute("t", "inlineStr");
2289+
break;
22862290

2287-
case cell::type::formula_string:
2288-
write_attribute("t", "str");
2289-
break;
2290-
}
2291+
case cell::type::number:
2292+
write_attribute("t", "n");
2293+
break;
22912294

2292-
//write_attribute("cm", "");
2293-
//write_attribute("vm", "");
2294-
//write_attribute("ph", "");
2295+
case cell::type::shared_string:
2296+
write_attribute("t", "s");
2297+
break;
22952298

2296-
// begin child elements
2299+
case cell::type::formula_string:
2300+
write_attribute("t", "str");
2301+
break;
2302+
}
22972303

2298-
if (cell.has_formula())
2299-
{
2300-
write_element(xmlns, "f", cell.formula());
2301-
}
2304+
//write_attribute("cm", "");
2305+
//write_attribute("vm", "");
2306+
//write_attribute("ph", "");
23022307

2303-
switch (cell.data_type())
2304-
{
2305-
case cell::type::empty:
2306-
break;
2308+
// begin child elements
23072309

2308-
case cell::type::boolean:
2309-
write_element(xmlns, "v", write_bool(cell.value<bool>()));
2310-
break;
2310+
if (cell.has_formula())
2311+
{
2312+
write_element(xmlns, "f", cell.formula());
2313+
}
23112314

2312-
case cell::type::date:
2313-
write_element(xmlns, "v", cell.value<std::string>());
2314-
break;
2315+
switch (cell.data_type())
2316+
{
2317+
case cell::type::empty:
2318+
break;
23152319

2316-
case cell::type::error:
2317-
write_element(xmlns, "v", cell.value<std::string>());
2318-
break;
2320+
case cell::type::boolean:
2321+
write_element(xmlns, "v", write_bool(cell.value<bool>()));
2322+
break;
23192323

2320-
case cell::type::inline_string:
2321-
write_start_element(xmlns, "is");
2322-
// TODO: make a write_rich_text method and use that here
2323-
write_element(xmlns, "t", cell.value<std::string>());
2324-
write_end_element(xmlns, "is");
2325-
break;
2324+
case cell::type::date:
2325+
write_element(xmlns, "v", cell.value<std::string>());
2326+
break;
23262327

2327-
case cell::type::number:
2328-
write_start_element(xmlns, "v");
2328+
case cell::type::error:
2329+
write_element(xmlns, "v", cell.value<std::string>());
2330+
break;
23292331

2330-
if (is_integral(cell.value<double>()))
2331-
{
2332-
write_characters(static_cast<std::int64_t>(cell.value<double>()));
2333-
}
2334-
else
2335-
{
2336-
std::stringstream ss;
2337-
ss.precision(20);
2338-
ss << cell.value<double>();
2339-
write_characters(ss.str());
2340-
}
2332+
case cell::type::inline_string:
2333+
write_start_element(xmlns, "is");
2334+
// TODO: make a write_rich_text method and use that here
2335+
write_element(xmlns, "t", cell.value<std::string>());
2336+
write_end_element(xmlns, "is");
2337+
break;
23412338

2342-
write_end_element(xmlns, "v");
2343-
break;
2339+
case cell::type::number:
2340+
write_start_element(xmlns, "v");
23442341

2345-
case cell::type::shared_string:
2346-
write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
2347-
break;
2342+
if (is_integral(cell.value<double>()))
2343+
{
2344+
write_characters(static_cast<std::int64_t>(cell.value<double>()));
2345+
}
2346+
else
2347+
{
2348+
std::stringstream ss;
2349+
ss.precision(20);
2350+
ss << cell.value<double>();
2351+
write_characters(ss.str());
2352+
}
23482353

2349-
case cell::type::formula_string:
2350-
write_element(xmlns, "v", cell.value<std::string>());
2351-
break;
2352-
}
2354+
write_end_element(xmlns, "v");
2355+
break;
2356+
2357+
case cell::type::shared_string:
2358+
write_element(xmlns, "v", static_cast<std::size_t>(cell.d_->value_numeric_));
2359+
break;
23532360

2354-
write_end_element(xmlns, "c");
2361+
case cell::type::formula_string:
2362+
write_element(xmlns, "v", cell.value<std::string>());
2363+
break;
2364+
}
2365+
2366+
write_end_element(xmlns, "c");
2367+
}
23552368
}
23562369

23572370
write_end_element(xmlns, "row");

0 commit comments

Comments
 (0)