Branch data TLA Line data Source code
1 : : // Copyright (c) 2014-2022 Thomas Fussell
2 : : // Copyright (c) 2010-2015 openpyxl
3 : : // Copyright (c) 2024-2025 xlnt-community
4 : : //
5 : : // Permission is hereby granted, free of charge, to any person obtaining a copy
6 : : // of this software and associated documentation files (the "Software"), to deal
7 : : // in the Software without restriction, including without limitation the rights
8 : : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : : // copies of the Software, and to permit persons to whom the Software is
10 : : // furnished to do so, subject to the following conditions:
11 : : //
12 : : // The above copyright notice and this permission notice shall be included in
13 : : // all copies or substantial portions of the Software.
14 : : //
15 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : : // THE SOFTWARE
22 : : //
23 : : // @license: http://www.opensource.org/licenses/mit-license.php
24 : : // @author: see AUTHORS file
25 : :
26 : : #include <algorithm>
27 : : #include <cmath>
28 : :
29 : : #include <xlnt/cell/cell.hpp>
30 : : #include <xlnt/cell/cell_reference.hpp>
31 : : #include <xlnt/cell/index_types.hpp>
32 : : #include <xlnt/packaging/relationship.hpp>
33 : : #include <xlnt/utils/date.hpp>
34 : : #include <xlnt/utils/datetime.hpp>
35 : : #include <xlnt/utils/exceptions.hpp>
36 : : #include <xlnt/utils/numeric.hpp>
37 : : #include <xlnt/workbook/named_range.hpp>
38 : : #include <xlnt/workbook/workbook.hpp>
39 : : #include <xlnt/workbook/worksheet_iterator.hpp>
40 : : #include <xlnt/worksheet/cell_iterator.hpp>
41 : : #include <xlnt/worksheet/column_properties.hpp>
42 : : #include <xlnt/worksheet/header_footer.hpp>
43 : : #include <xlnt/worksheet/range.hpp>
44 : : #include <xlnt/worksheet/range_iterator.hpp>
45 : : #include <xlnt/worksheet/range_reference.hpp>
46 : : #include <xlnt/worksheet/row_properties.hpp>
47 : : #include <xlnt/worksheet/worksheet.hpp>
48 : : #include <detail/constants.hpp>
49 : : #include <detail/default_case.hpp>
50 : : #include <detail/implementations/cell_impl.hpp>
51 : : #include <detail/implementations/workbook_impl.hpp>
52 : : #include <detail/implementations/worksheet_impl.hpp>
53 : : #include <detail/unicode.hpp>
54 : :
55 : : namespace {
56 : :
57 :CBC 52 : int points_to_pixels(double points, double dpi)
58 : : {
59 : 52 : return static_cast<int>(std::ceil(points * dpi / 72));
60 : : }
61 : :
62 : : } // namespace
63 : :
64 : : namespace xlnt {
65 : :
66 : 6 : worksheet::worksheet()
67 : 6 : : d_(nullptr)
68 : : {
69 : 6 : }
70 : :
71 : 3110 : worksheet::worksheet(detail::worksheet_impl *d)
72 : 3110 : : d_(d)
73 : : {
74 : 3110 : }
75 : :
76 : 4395 : worksheet::worksheet(const worksheet &rhs)
77 : 4395 : : d_(rhs.d_)
78 : : {
79 : 4395 : }
80 : :
81 : 4 : bool worksheet::has_frozen_panes() const
82 : : {
83 [ + + ]: 8 : return !d_->views_.empty() && d_->views_.front().has_pane()
84 [ + - - + ]: 8 : && (d_->views_.front().pane().state == pane_state::frozen
85 [ - - ]: 4 : || d_->views_.front().pane().state == pane_state::frozen_split);
86 : : }
87 : :
88 : 6 : void worksheet::create_named_range(const std::string &name, const std::string &reference_string)
89 : : {
90 [ + + ]: 6 : create_named_range(name, range_reference(reference_string));
91 : 4 : }
92 : :
93 : 12 : void worksheet::create_named_range(const std::string &name, const range_reference &reference)
94 : : {
95 : : try
96 : : {
97 [ + ]: 12 : auto temp = cell_reference::split_reference(name);
98 : :
99 : : // name is a valid reference, make sure it's outside the allowed range
100 : :
101 [ + + + + : 4 : if (column_t(temp.first).index <= column_t("XFD").index && temp.second <= 1048576)
+ + + + ]
102 : : {
103 [ + ]: 2 : throw invalid_parameter(); //("named range name must be outside the range A1-XFD1048576");
104 : : }
105 : 4 : }
106 [ + + ]: 10 : catch (xlnt::invalid_cell_reference &)
107 : : {
108 : : // name is not a valid reference, that's good
109 [ + ]: 8 : }
110 : :
111 : 10 : std::vector<named_range::target> targets;
112 [ + ]: 10 : targets.push_back({*this, reference});
113 : :
114 [ + + + ]: 10 : d_->named_ranges_[name] = xlnt::named_range(name, targets);
115 : 10 : }
116 : :
117 : 109 : cell worksheet::operator[](const cell_reference &ref)
118 : : {
119 : 109 : return cell(ref);
120 : : }
121 : :
122 : 62 : std::vector<range_reference> worksheet::merged_ranges() const
123 : : {
124 : 62 : return d_->merged_cells_;
125 : : }
126 : :
127 : 54 : bool worksheet::has_page_margins() const
128 : : {
129 : 54 : return d_->page_margins_.is_set();
130 : : }
131 : :
132 : 235 : bool worksheet::has_page_setup() const
133 : : {
134 : 235 : return d_->page_setup_.is_set();
135 : : }
136 : :
137 : 283 : page_margins worksheet::page_margins() const
138 : : {
139 : 283 : return d_->page_margins_.get();
140 : : }
141 : :
142 : 365 : void worksheet::page_margins(const class page_margins &margins)
143 : : {
144 : 365 : d_->page_margins_ = margins;
145 : 365 : }
146 : :
147 : 1 : void worksheet::auto_filter(const std::string &reference_string)
148 : : {
149 [ + ]: 1 : auto_filter(range_reference(reference_string));
150 : 1 : }
151 : :
152 : 2 : void worksheet::auto_filter(const range_reference &reference)
153 : : {
154 : 2 : d_->auto_filter_ = reference;
155 : 2 : }
156 : :
157 :UBC 0 : void worksheet::auto_filter(const xlnt::range &range)
158 : : {
159 [ # ]: 0 : auto_filter(range.reference());
160 : 0 : }
161 : :
162 :CBC 3 : range_reference worksheet::auto_filter() const
163 : : {
164 : 3 : return d_->auto_filter_.get();
165 : : }
166 : :
167 : 109 : bool worksheet::has_auto_filter() const
168 : : {
169 : 109 : return d_->auto_filter_.is_set();
170 : : }
171 : :
172 :UBC 0 : void worksheet::clear_auto_filter()
173 : : {
174 : 0 : d_->auto_filter_.clear();
175 : 0 : }
176 : :
177 :CBC 36 : void worksheet::page_setup(const struct page_setup &setup)
178 : : {
179 : 36 : d_->page_setup_ = setup;
180 : 36 : }
181 : :
182 : 71 : page_setup worksheet::page_setup() const
183 : : {
184 [ - + ]: 71 : if (!has_page_setup())
185 : : {
186 [ # ]:UBC 0 : throw invalid_attribute();
187 : : }
188 : :
189 :CBC 71 : return d_->page_setup_.get();
190 : : }
191 : :
192 : 539 : workbook worksheet::workbook()
193 : : {
194 [ + ]: 539 : return d_->parent_;
195 : : }
196 : :
197 : 308 : const workbook worksheet::workbook() const
198 : : {
199 [ + ]: 308 : return d_->parent_;
200 : : }
201 : :
202 : 1 : void worksheet::garbage_collect()
203 : : {
204 : 1 : auto cell_iter = d_->cell_map_.begin();
205 : :
206 [ + + ]: 2 : while (cell_iter != d_->cell_map_.end())
207 : : {
208 [ + + - + ]: 1 : if (xlnt::cell(&cell_iter->second).garbage_collectible())
209 : : {
210 [ # ]:UBC 0 : cell_iter = d_->cell_map_.erase(cell_iter);
211 : : }
212 : : else
213 : : {
214 :CBC 1 : ++cell_iter;
215 : : }
216 : : }
217 : 1 : }
218 : :
219 :UBC 0 : void worksheet::id(std::size_t id)
220 : : {
221 : 0 : d_->id_ = id;
222 : 0 : }
223 : :
224 :CBC 288 : std::size_t worksheet::id() const
225 : : {
226 : 288 : return d_->id_;
227 : : }
228 : :
229 : 1301 : std::string worksheet::title() const
230 : : {
231 : 1301 : return d_->title_;
232 : : }
233 : :
234 : 36 : void worksheet::title(const std::string &title)
235 : : {
236 : : // do no work if we don't need to
237 [ + + ]: 36 : if (d_->title_ == title)
238 : : {
239 : 6 : return;
240 : : }
241 : : // excel limits worksheet titles to 31 characters
242 [ + + + + : 30 : if (title.empty() || detail::string_length(title) > 31)
+ + + ]
243 : : {
244 [ + ]: 2 : throw invalid_sheet_title(title);
245 : : }
246 : : // invalid characters in a worksheet name
247 [ + + ]: 27 : if (title.find_first_of("*:/\\?[]") != std::string::npos)
248 : : {
249 [ + ]: 7 : throw invalid_sheet_title(title);
250 : : }
251 : : // try and insert the new name into the worksheets map
252 : : // if the insert fails, we have a duplicate sheet name
253 [ + + ]: 40 : auto insert_result = workbook().d_->sheet_title_rel_id_map_.insert(
254 [ + + + ]: 40 : std::make_pair(title, workbook().d_->sheet_title_rel_id_map_[d_->title_]));
255 [ + + ]: 20 : if (!insert_result.second) // insert failed, duplication detected
256 : : {
257 [ + ]: 2 : throw invalid_sheet_title(title);
258 : : }
259 : : // if the insert succeeded (i.e. wasn't a duplicate sheet name)
260 : : // update the worksheet title and remove the old relation
261 [ + + ]: 18 : workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
262 [ + ]: 18 : d_->title_ = title;
263 : :
264 [ + + ]: 18 : workbook().update_sheet_properties();
265 : : }
266 : :
267 : 2 : cell_reference worksheet::frozen_panes() const
268 : : {
269 [ - + ]: 2 : if (!has_frozen_panes())
270 : : {
271 [ # ]:UBC 0 : throw xlnt::invalid_attribute();
272 : : }
273 : :
274 :CBC 2 : return d_->views_.front().pane().top_left_cell.get();
275 : : }
276 : :
277 : 2 : void worksheet::freeze_panes(xlnt::cell top_left_cell)
278 : : {
279 [ + + ]: 2 : freeze_panes(top_left_cell.reference());
280 : 2 : }
281 : :
282 : 7 : void worksheet::freeze_panes(const cell_reference &ref)
283 : : {
284 [ + + ]: 7 : if (ref == "A1")
285 : : {
286 : 1 : unfreeze_panes();
287 : 1 : return;
288 : : }
289 [ - + ]: 6 : if (!has_view())
290 : : {
291 [ # ]:UBC 0 : d_->views_.push_back(sheet_view());
292 : : }
293 : :
294 :CBC 6 : auto &primary_view = d_->views_.front();
295 [ + - ]: 6 : if (!primary_view.has_pane())
296 : : {
297 [ + ]: 6 : primary_view.pane(pane());
298 : : }
299 : :
300 : 6 : primary_view.pane().top_left_cell = ref;
301 : 6 : primary_view.pane().state = pane_state::frozen;
302 : :
303 : 6 : primary_view.clear_selections();
304 [ + + + + ]: 6 : if (ref.column() == "A") // no column is frozen
305 : : {
306 [ + + ]: 1 : primary_view.add_selection(selection(pane_corner::bottom_left, ref));
307 : 1 : primary_view.pane().active_pane = pane_corner::bottom_left;
308 : 1 : primary_view.pane().y_split = ref.row() - 1;
309 : : }
310 [ + + ]: 5 : else if (ref.row() == 1) // no row is frozen
311 : : {
312 [ + + ]: 1 : primary_view.add_selection(selection(pane_corner::top_right, ref));
313 : 1 : primary_view.pane().active_pane = pane_corner::top_right;
314 [ + + + ]: 1 : primary_view.pane().x_split = ref.column_index() - 1;
315 : : }
316 : : else // column and row is frozen
317 : : {
318 [ + + + + ]: 4 : primary_view.add_selection(selection(pane_corner::top_right, cell_reference(ref.column(), 1)));
319 [ + + + + : 4 : primary_view.add_selection(selection(pane_corner::bottom_left, cell_reference(1, ref.row())));
+ ]
320 [ + + ]: 4 : primary_view.add_selection(selection(pane_corner::bottom_right, ref));
321 : 4 : primary_view.pane().active_pane = pane_corner::bottom_right;
322 [ + + + ]: 4 : primary_view.pane().x_split = ref.column_index() - 1;
323 : 4 : primary_view.pane().y_split = ref.row() - 1;
324 : : }
325 : : }
326 : :
327 : 2 : void worksheet::unfreeze_panes()
328 : : {
329 [ - + ]: 2 : if (!has_view()) return;
330 : :
331 : 2 : auto &primary_view = d_->views_.front();
332 : :
333 : 2 : primary_view.clear_selections();
334 : 2 : primary_view.clear_pane();
335 : : }
336 : :
337 : 1 : void worksheet::active_cell(const cell_reference &ref)
338 : : {
339 [ - + ]: 1 : if (!has_view())
340 : : {
341 [ # ]:UBC 0 : d_->views_.push_back(sheet_view());
342 : : }
343 : :
344 :CBC 1 : auto &primary_view = d_->views_.front();
345 : :
346 [ + - ]: 1 : if (!primary_view.has_selections())
347 : : {
348 [ + + ]: 1 : primary_view.add_selection(selection(pane_corner::bottom_right, ref));
349 : : }
350 : : else
351 : : {
352 :UBC 0 : primary_view.selection(0).active_cell(ref);
353 : : }
354 :CBC 1 : }
355 : :
356 : 3 : bool worksheet::has_active_cell() const
357 : : {
358 [ - + ]: 3 : if (!has_view()) return false;
359 : 3 : auto &primary_view = d_->views_.front();
360 [ + + ]: 3 : if (!primary_view.has_selections()) return false;
361 [ + + ]: 2 : auto primary_selection = primary_view.selection(0);
362 : :
363 : 2 : return primary_selection.has_active_cell();
364 : 2 : }
365 : :
366 : 2 : cell_reference worksheet::active_cell() const
367 : : {
368 [ - + ]: 2 : if (!has_view())
369 : : {
370 [ # # ]:UBC 0 : throw xlnt::exception("Worksheet has no view.");
371 : : }
372 : :
373 :CBC 2 : auto &primary_view = d_->views_.front();
374 : :
375 [ - + ]: 2 : if (!primary_view.has_selections())
376 : : {
377 [ # # ]:UBC 0 : throw xlnt::exception("Default worksheet view has no selections.");
378 : : }
379 : :
380 :CBC 2 : return primary_view.selection(0).active_cell();
381 : : }
382 : :
383 : 2935 : cell worksheet::cell(const cell_reference &reference)
384 : : {
385 [ + ]: 2935 : auto match = d_->cell_map_.find(reference);
386 [ + + ]: 2935 : if (match == d_->cell_map_.end())
387 : : {
388 [ + ]: 1110 : auto impl = detail::cell_impl();
389 : 1110 : impl.parent_ = d_;
390 [ + + ]: 1110 : impl.column_ = reference.column_index();
391 [ + ]: 1110 : impl.row_ = reference.row();
392 : :
393 [ + ]: 1110 : match = d_->cell_map_.emplace(reference, impl).first;
394 : 1110 : }
395 [ + ]: 2935 : return xlnt::cell(&match->second);
396 : : }
397 : :
398 : 37 : const cell worksheet::cell(const cell_reference &reference) const
399 : : {
400 [ + ]: 37 : const auto match = d_->cell_map_.find(reference);
401 [ + + ]: 37 : if (match == d_->cell_map_.end())
402 : : {
403 [ + ]: 1 : throw xlnt::invalid_parameter("Requested cell doesn't exist.");
404 : : }
405 [ + ]: 36 : return xlnt::cell(&match->second);
406 : : }
407 : :
408 : 23 : cell worksheet::cell(xlnt::column_t column, row_t row)
409 : : {
410 [ + + ]: 23 : return cell(cell_reference(column, row));
411 : : }
412 : :
413 :UBC 0 : const cell worksheet::cell(xlnt::column_t column, row_t row) const
414 : : {
415 [ # # ]: 0 : return cell(cell_reference(column, row));
416 : : }
417 : :
418 :CBC 4069 : bool worksheet::has_cell(const cell_reference &reference) const
419 : : {
420 [ + ]: 4069 : const auto cell = d_->cell_map_.find(reference);
421 : 4069 : return cell != d_->cell_map_.cend();
422 : : }
423 : :
424 : 2771 : bool worksheet::has_row_properties(row_t row) const
425 : : {
426 [ + ]: 2771 : return d_->row_properties_.find(row) != d_->row_properties_.end();
427 : : }
428 : :
429 : 9 : range worksheet::named_range(const std::string &name)
430 : : {
431 [ + + + + ]: 9 : if (!workbook().has_named_range(name))
432 : : {
433 [ + ]: 1 : throw key_not_found();
434 : : }
435 : :
436 [ + + ]: 8 : if (!has_named_range(name))
437 : : {
438 [ + ]: 1 : throw key_not_found();
439 : : }
440 : :
441 : 7 : return range(d_->named_ranges_[name].targets()[0].second);
442 : : }
443 : :
444 :UBC 0 : const range worksheet::named_range(const std::string &name) const
445 : : {
446 [ # # # # ]: 0 : if (!workbook().has_named_range(name))
447 : : {
448 [ # ]: 0 : throw key_not_found();
449 : : }
450 : :
451 [ # # ]: 0 : if (!has_named_range(name))
452 : : {
453 [ # ]: 0 : throw key_not_found();
454 : : }
455 : :
456 : 0 : return range(d_->named_ranges_[name].targets()[0].second);
457 : : }
458 : :
459 :CBC 58 : column_t worksheet::lowest_column() const
460 : : {
461 [ + + ]: 58 : if (d_->cell_map_.empty())
462 : : {
463 [ + ]: 20 : return constants::min_column();
464 : : }
465 : :
466 [ + ]: 38 : auto lowest = constants::max_column();
467 : :
468 [ + + ]: 1001 : for (auto &cell : d_->cell_map_)
469 : : {
470 [ + + ]: 963 : lowest = std::min(lowest, cell.first.column());
471 : : }
472 : :
473 : 38 : return lowest;
474 : : }
475 : :
476 : 54 : column_t worksheet::lowest_column_or_props() const
477 : : {
478 [ + ]: 54 : auto lowest = lowest_column();
479 : :
480 [ + + + + : 54 : if (d_->cell_map_.empty() && !d_->column_properties_.empty())
+ + ]
481 : : {
482 : 1 : lowest = d_->column_properties_.begin()->first;
483 : : }
484 : :
485 [ + + ]: 1388 : for (auto &props : d_->column_properties_)
486 : : {
487 [ + ]: 1334 : lowest = std::min(lowest, props.first);
488 : : }
489 : :
490 : 54 : return lowest;
491 : : }
492 : :
493 : 80 : row_t worksheet::lowest_row() const
494 : : {
495 [ + + ]: 80 : if (d_->cell_map_.empty())
496 : : {
497 [ + ]: 34 : return constants::min_row();
498 : : }
499 : :
500 [ + ]: 46 : auto lowest = constants::max_row();
501 : :
502 [ + + ]: 1221 : for (auto &cell : d_->cell_map_)
503 : : {
504 [ + ]: 1175 : lowest = std::min(lowest, cell.first.row());
505 : : }
506 : :
507 : 46 : return lowest;
508 : : }
509 : :
510 : 54 : row_t worksheet::lowest_row_or_props() const
511 : : {
512 [ + ]: 54 : auto lowest = lowest_row();
513 : :
514 [ + + + + : 54 : if (d_->cell_map_.empty() && !d_->row_properties_.empty())
+ + ]
515 : : {
516 : 1 : lowest = d_->row_properties_.begin()->first;
517 : : }
518 : :
519 [ + + ]: 1337 : for (auto &props : d_->row_properties_)
520 : : {
521 : 1283 : lowest = std::min(lowest, props.first);
522 : : }
523 : :
524 : 54 : return lowest;
525 : : }
526 : :
527 : 86 : row_t worksheet::highest_row() const
528 : : {
529 [ + ]: 86 : auto highest = constants::min_row();
530 : :
531 [ + + ]: 1819 : for (auto &cell : d_->cell_map_)
532 : : {
533 [ + ]: 1733 : highest = std::max(highest, cell.first.row());
534 : : }
535 : :
536 : 86 : return highest;
537 : : }
538 : :
539 : 54 : row_t worksheet::highest_row_or_props() const
540 : : {
541 [ + ]: 54 : auto highest = highest_row();
542 : :
543 [ + + + + : 54 : if (d_->cell_map_.empty() && !d_->row_properties_.empty())
+ + ]
544 : : {
545 : 1 : highest = d_->row_properties_.begin()->first;
546 : : }
547 : :
548 [ + + ]: 1337 : for (auto &props : d_->row_properties_)
549 : : {
550 : 1283 : highest = std::max(highest, props.first);
551 : : }
552 : :
553 : 54 : return highest;
554 : : }
555 : :
556 : 59 : column_t worksheet::highest_column() const
557 : : {
558 [ + ]: 59 : auto highest = constants::min_column();
559 : :
560 [ + + ]: 1023 : for (auto &cell : d_->cell_map_)
561 : : {
562 [ + + ]: 964 : highest = std::max(highest, cell.first.column());
563 : : }
564 : :
565 : 59 : return highest;
566 : : }
567 : :
568 : 54 : column_t worksheet::highest_column_or_props() const
569 : : {
570 [ + ]: 54 : auto highest = highest_column();
571 : :
572 [ + + + + : 54 : if (d_->cell_map_.empty() && !d_->column_properties_.empty())
+ + ]
573 : : {
574 : 1 : highest = d_->column_properties_.begin()->first;
575 : : }
576 : :
577 [ + + ]: 1388 : for (auto &props : d_->column_properties_)
578 : : {
579 [ + ]: 1334 : highest = std::max(highest, props.first);
580 : : }
581 : :
582 : 54 : return highest;
583 : : }
584 : :
585 : 167 : range_reference worksheet::calculate_dimension(bool skip_null, bool skip_row_props) const
586 : : {
587 : : // partially optimised version of:
588 : : // return range_reference(lowest_column(), lowest_row_or_props(),
589 : : // highest_column(), highest_row_or_props());
590 : : //
591 [ + + + - : 167 : if (d_->cell_map_.empty() && d_->row_properties_.empty())
+ + ]
592 : : {
593 : : return range_reference(constants::min_column(), constants::min_row(),
594 [ + + + + : 29 : constants::min_column(), constants::min_row());
+ ]
595 : : }
596 : :
597 : : // if skip_null = false, min row = min_row() and min column = min_column()
598 : : // in order to include first empty rows and columns
599 [ + + + + ]: 138 : row_t min_row_prop = skip_null? constants::max_row() : constants::min_row();
600 [ + ]: 138 : row_t max_row_prop = constants::min_row();
601 [ + + ]: 138 : if (!skip_row_props)
602 : : {
603 [ + + ]: 2827 : for (const auto &row_prop : d_->row_properties_)
604 : : {
605 [ + + ]: 2734 : if(skip_null){
606 : 2732 : min_row_prop = std::min(min_row_prop, row_prop.first);
607 : : }
608 : 2734 : max_row_prop = std::max(max_row_prop, row_prop.first);
609 : : }
610 : : }
611 [ - + ]: 138 : if (d_->cell_map_.empty())
612 : : {
613 : : return range_reference(constants::min_column(), min_row_prop,
614 [ # # # ]:UBC 0 : constants::min_column(), max_row_prop);
615 : : }
616 : : // find min and max row/column in cell map
617 [ + + + + ]:CBC 138 : column_t min_col = skip_null? constants::max_column() : constants::min_column();
618 [ + ]: 138 : column_t max_col = constants::min_column();
619 : 138 : row_t min_row = min_row_prop;
620 : 138 : row_t max_row = max_row_prop;
621 [ + + ]: 3336 : for (auto &c : d_->cell_map_)
622 : : {
623 [ + + ]: 3198 : if(skip_null){
624 [ + ]: 3165 : min_col = std::min(min_col, c.second.column_);
625 : 3165 : min_row = std::min(min_row, c.second.row_);
626 : : }
627 [ + ]: 3198 : max_col = std::max(max_col, c.second.column_);
628 : 3198 : max_row = std::max(max_row, c.second.row_);
629 : : }
630 [ + ]: 138 : return range_reference(min_col, min_row, max_col, max_row);
631 : : }
632 : :
633 : 24 : range worksheet::range(const std::string &reference_string)
634 : : {
635 [ + + ]: 24 : if (has_named_range(reference_string))
636 : : {
637 : 3 : return named_range(reference_string);
638 : : }
639 : :
640 [ + + ]: 21 : return range(range_reference(reference_string));
641 : : }
642 : :
643 : 1 : const range worksheet::range(const std::string &reference_string) const
644 : : {
645 [ - + ]: 1 : if (has_named_range(reference_string))
646 : : {
647 :UBC 0 : return named_range(reference_string);
648 : : }
649 : :
650 [ + + ]:CBC 1 : return range(range_reference(reference_string));
651 : : }
652 : :
653 : 41 : range worksheet::range(const range_reference &reference)
654 : : {
655 [ + ]: 41 : return xlnt::range(*this, reference);
656 : : }
657 : :
658 : 1 : const range worksheet::range(const range_reference &reference) const
659 : : {
660 [ + ]: 1 : return xlnt::range(*this, reference);
661 : : }
662 : :
663 : 9 : void worksheet::merge_cells(const std::string &reference_string)
664 : : {
665 [ + + ]: 9 : merge_cells(range_reference(reference_string));
666 : 9 : }
667 : :
668 : 2 : void worksheet::unmerge_cells(const std::string &reference_string)
669 : : {
670 [ + + ]: 2 : unmerge_cells(range_reference(reference_string));
671 : 1 : }
672 : :
673 : 11 : void worksheet::merge_cells(const range_reference &reference)
674 : : {
675 : 11 : d_->merged_cells_.push_back(reference);
676 : 11 : bool first = true;
677 : :
678 [ + + + + : 149 : for (auto row : range(reference))
+ + + + ]
679 : : {
680 [ + + + + : 827 : for (auto cell : row)
+ + ]
681 : : {
682 [ + ]: 758 : cell.merged(true);
683 : :
684 [ + + ]: 758 : if (!first)
685 : : {
686 [ + + + ]: 747 : if (cell.data_type() == cell::type::shared_string)
687 : : {
688 [ + ]: 1 : cell.value("");
689 : : }
690 : : else
691 : : {
692 [ + ]: 746 : cell.clear_value();
693 : : }
694 : : }
695 : :
696 [ + ]: 758 : first = false;
697 : : }
698 : 11 : }
699 : 11 : }
700 : :
701 : 2 : void worksheet::unmerge_cells(const range_reference &reference)
702 : : {
703 [ + ]: 2 : auto match = std::find(d_->merged_cells_.begin(), d_->merged_cells_.end(), reference);
704 : :
705 [ + + ]: 2 : if (match == d_->merged_cells_.end())
706 : : {
707 [ + ]: 1 : throw invalid_parameter();
708 : : }
709 : :
710 [ + ]: 1 : d_->merged_cells_.erase(match);
711 : :
712 [ + + + + : 9 : for (auto row : range(reference))
+ + + + ]
713 : : {
714 [ + + + + : 36 : for (auto cell : row)
+ + + ]
715 : : {
716 [ + ]: 16 : cell.merged(false);
717 : : }
718 : 1 : }
719 : 1 : }
720 : :
721 :UBC 0 : row_t worksheet::next_row() const
722 : : {
723 : 0 : auto row = highest_row() + 1;
724 : :
725 [ # # # # : 0 : if (row == 2 && d_->cell_map_.size() == 0)
# # ]
726 : : {
727 : 0 : row = 1;
728 : : }
729 : :
730 : 0 : return row;
731 : : }
732 : :
733 :CBC 39 : xlnt::range worksheet::rows(bool skip_null)
734 : : {
735 [ + + ]: 39 : return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::row, skip_null);
736 : : }
737 : :
738 : 6 : const xlnt::range worksheet::rows(bool skip_null) const
739 : : {
740 [ + + ]: 6 : return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::row, skip_null);
741 : : }
742 : :
743 : 16 : xlnt::range worksheet::columns(bool skip_null)
744 : : {
745 [ + + ]: 16 : return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::column, skip_null);
746 : : }
747 : :
748 : 2 : const xlnt::range worksheet::columns(bool skip_null) const
749 : : {
750 [ + + ]: 2 : return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::column, skip_null);
751 : : }
752 : :
753 : : /*
754 : : //TODO: finish implementing cell_iterator wrapping before uncommenting
755 : :
756 : : cell_vector worksheet::cells(bool skip_null)
757 : : {
758 : : const auto dimension = calculate_dimension();
759 : : return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
760 : : }
761 : :
762 : : const cell_vector worksheet::cells(bool skip_null) const
763 : : {
764 : : const auto dimension = calculate_dimension();
765 : : return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
766 : : }
767 : : */
768 : :
769 : 7 : void worksheet::clear_cell(const cell_reference &ref)
770 : : {
771 : 7 : d_->cell_map_.erase(ref);
772 : : // TODO: garbage collect newly unreferenced resources such as styles?
773 : 7 : }
774 : :
775 : 1 : void worksheet::clear_row(row_t row)
776 : : {
777 [ + + ]: 141 : for (auto it = d_->cell_map_.begin(); it != d_->cell_map_.end();)
778 : : {
779 [ + + + ]: 140 : if (it->first.row() == row)
780 : : {
781 [ + ]: 4 : it = d_->cell_map_.erase(it);
782 : : }
783 : : else
784 : : {
785 : 136 : ++it;
786 : : }
787 : : }
788 : 1 : d_->row_properties_.erase(row);
789 : : // TODO: garbage collect newly unreferenced resources such as styles?
790 : 1 : }
791 : :
792 : 3 : void worksheet::insert_rows(row_t row, std::uint32_t amount)
793 : : {
794 : 3 : move_cells(row, amount, row_or_col_t::row);
795 : 2 : }
796 : :
797 : 2 : void worksheet::insert_columns(column_t column, std::uint32_t amount)
798 : : {
799 : 2 : move_cells(column.index, amount, row_or_col_t::column);
800 : 2 : }
801 : :
802 : 6 : void worksheet::delete_rows(row_t row, std::uint32_t amount)
803 : : {
804 : 6 : move_cells(row + amount, amount, row_or_col_t::row, true);
805 : 6 : }
806 : :
807 : 2 : void worksheet::delete_columns(column_t column, std::uint32_t amount)
808 : : {
809 : 2 : move_cells(column.index + amount, amount, row_or_col_t::column, true);
810 : 2 : }
811 : :
812 : 13 : void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse)
813 : : {
814 [ + + - + ]: 13 : if (reverse && amount > min_index)
815 : : {
816 [ # ]:UBC 0 : throw xlnt::invalid_parameter();
817 : : }
818 : :
819 [ + + + + :CBC 13 : if ((!reverse && row_or_col == row_or_col_t::row && min_index > constants::max_row() - amount) || (!reverse && row_or_col == row_or_col_t::column && min_index > constants::max_column() - amount))
+ + + + +
+ + + + +
+ - + +
+ ]
820 : : {
821 [ + + ]: 3 : throw xlnt::exception("Cannot move cells as they would be outside the maximum bounds of the spreadsheet");
822 : : }
823 : :
824 : 12 : std::vector<detail::cell_impl> cells_to_move;
825 : :
826 : 12 : auto cell_iter = d_->cell_map_.cbegin();
827 [ + + ]: 107 : while (cell_iter != d_->cell_map_.cend())
828 : : {
829 : : std::uint32_t current_index;
830 [ + + - ]: 95 : switch (row_or_col)
831 : : {
832 : 51 : case row_or_col_t::row:
833 [ + ]: 51 : current_index = cell_iter->first.row();
834 : 51 : break;
835 : 44 : case row_or_col_t::column:
836 [ + ]: 44 : current_index = cell_iter->first.column().index;
837 : 44 : break;
838 :UBC 0 : default:
839 [ # ]: 0 : throw xlnt::unhandled_switch_case();
840 : : }
841 : :
842 [ + + ]:CBC 95 : if (current_index >= min_index) // extract cells to be moved
843 : : {
844 [ + ]: 42 : auto cell = cell_iter->second;
845 [ + + ]: 42 : if (row_or_col == row_or_col_t::row)
846 : : {
847 [ + + ]: 26 : cell.row_ = reverse ? cell.row_ - amount : cell.row_ + amount;
848 : : }
849 [ + - ]: 16 : else if (row_or_col == row_or_col_t::column)
850 : : {
851 [ + + + ]: 16 : cell.column_ = reverse ? cell.column_.index - amount : cell.column_.index + amount;
852 : : }
853 : :
854 [ + ]: 42 : cells_to_move.push_back(cell);
855 [ + ]: 42 : cell_iter = d_->cell_map_.erase(cell_iter);
856 : 42 : }
857 [ + + + + ]: 53 : else if (reverse && current_index >= min_index - amount) // delete destination cells
858 : : {
859 [ + ]: 21 : cell_iter = d_->cell_map_.erase(cell_iter);
860 : : }
861 : : else // skip other cells
862 : : {
863 : 32 : ++cell_iter;
864 : : }
865 : : }
866 : :
867 [ + + ]: 54 : for (auto &cell : cells_to_move)
868 : : {
869 [ + + + ]: 42 : d_->cell_map_[cell_reference(cell.column_, cell.row_)] = cell;
870 : : }
871 : :
872 [ + + ]: 12 : if (row_or_col == row_or_col_t::row)
873 : : {
874 : 8 : std::vector<std::pair<row_t, xlnt::row_properties>> properties_to_move;
875 : :
876 : 8 : auto row_prop_iter = d_->row_properties_.cbegin();
877 [ + + ]: 16 : while (row_prop_iter != d_->row_properties_.cend())
878 : : {
879 : 8 : auto current_row = row_prop_iter->first;
880 [ + + ]: 8 : if (current_row >= min_index) // extract properties that need to be moved
881 : : {
882 [ + + ]: 3 : auto tmp_row = reverse ? current_row - amount : current_row + amount;
883 [ + + ]: 3 : properties_to_move.push_back({tmp_row, row_prop_iter->second});
884 [ + ]: 3 : row_prop_iter = d_->row_properties_.erase(row_prop_iter);
885 : : }
886 [ + + + + ]: 5 : else if (reverse && current_row >= min_index - amount) // clear properties of destination when in reverse
887 : : {
888 [ + ]: 3 : row_prop_iter = d_->row_properties_.erase(row_prop_iter);
889 : : }
890 : : else // skip the rest
891 : : {
892 : 2 : ++row_prop_iter;
893 : : }
894 : : }
895 : :
896 [ + + ]: 11 : for (const auto &prop : properties_to_move)
897 : : {
898 [ + ]: 3 : add_row_properties(prop.first, prop.second);
899 : : }
900 : 8 : }
901 [ + - ]: 4 : else if (row_or_col == row_or_col_t::column)
902 : : {
903 : 4 : std::vector<std::pair<column_t, xlnt::column_properties>> properties_to_move;
904 : :
905 : 4 : auto col_prop_iter = d_->column_properties_.cbegin();
906 [ + + ]: 10 : while (col_prop_iter != d_->column_properties_.cend())
907 : : {
908 : 6 : auto current_col = col_prop_iter->first.index;
909 [ + + ]: 6 : if (current_col >= min_index) // extract properties that need to be moved
910 : : {
911 [ + + + ]: 2 : auto tmp_column = column_t(reverse ? current_col - amount : current_col + amount);
912 [ + ]: 2 : properties_to_move.push_back({tmp_column, col_prop_iter->second});
913 [ + ]: 2 : col_prop_iter = d_->column_properties_.erase(col_prop_iter);
914 : : }
915 [ + + + + ]: 4 : else if (reverse && current_col >= min_index - amount) // clear properties of destination when in reverse
916 : : {
917 [ + ]: 2 : col_prop_iter = d_->column_properties_.erase(col_prop_iter);
918 : : }
919 : : else // skip the rest
920 : : {
921 : 2 : ++col_prop_iter;
922 : : }
923 : : }
924 : :
925 [ + + ]: 6 : for (auto &prop : properties_to_move)
926 : : {
927 [ + ]: 2 : add_column_properties(prop.first, prop.second);
928 : : }
929 : 4 : }
930 : :
931 : : // adjust merged cells
932 : 48 : auto shift_reference = [min_index, amount, row_or_col, reverse](cell_reference &ref) {
933 [ + + ]: 48 : auto index = row_or_col == row_or_col_t::row ? ref.row() : ref.column_index();
934 [ + + ]: 48 : if (index >= min_index)
935 : : {
936 [ + + ]: 28 : auto new_index = reverse ? index - amount : index + amount;
937 [ + + ]: 28 : if (row_or_col == row_or_col_t::row)
938 : : {
939 : 18 : ref.row(new_index);
940 : : }
941 [ + - ]: 10 : else if (row_or_col == row_or_col_t::column)
942 : : {
943 [ + + ]: 10 : ref.column_index(new_index);
944 : : }
945 : : }
946 : 48 : };
947 : :
948 [ + + ]: 36 : for (auto merged_cell = d_->merged_cells_.begin(); merged_cell != d_->merged_cells_.end(); ++merged_cell)
949 : : {
950 [ + ]: 24 : cell_reference new_top_left = merged_cell->top_left();
951 [ + ]: 24 : shift_reference(new_top_left);
952 : :
953 [ + ]: 24 : cell_reference new_bottom_right = merged_cell->bottom_right();
954 [ + ]: 24 : shift_reference(new_bottom_right);
955 : :
956 [ + ]: 24 : range_reference new_range{new_top_left, new_bottom_right};
957 [ + + + ]: 24 : if (*merged_cell != new_range)
958 : : {
959 : 16 : *merged_cell = new_range;
960 : : }
961 : : }
962 : 12 : }
963 : :
964 : 2072 : bool worksheet::operator==(const worksheet &other) const
965 : : {
966 : 2072 : return compare(other, true);
967 : : }
968 : :
969 : 2074 : bool worksheet::compare(const worksheet &other, bool compare_by_reference) const
970 : : {
971 [ + + ]: 2074 : if (compare_by_reference)
972 : : {
973 : 2072 : return d_ == other.d_;
974 : : }
975 : : else
976 : : {
977 : 2 : return *d_ == *other.d_;
978 : : }
979 : : }
980 : :
981 : 1 : bool worksheet::operator!=(const worksheet &other) const
982 : : {
983 : 1 : return !(*this == other);
984 : : }
985 : :
986 :UBC 0 : bool worksheet::operator==(std::nullptr_t) const
987 : : {
988 : 0 : return d_ == nullptr;
989 : : }
990 : :
991 : 0 : bool worksheet::operator!=(std::nullptr_t) const
992 : : {
993 : 0 : return d_ != nullptr;
994 : : }
995 : :
996 :CBC 6 : void worksheet::operator=(const worksheet &other)
997 : : {
998 : 6 : d_ = other.d_;
999 : 6 : }
1000 : :
1001 :UBC 0 : const cell worksheet::operator[](const cell_reference &ref) const
1002 : : {
1003 : 0 : return cell(ref);
1004 : : }
1005 : :
1006 :CBC 62 : bool worksheet::has_named_range(const std::string &name) const
1007 : : {
1008 [ + ]: 62 : return d_->named_ranges_.find(name) != d_->named_ranges_.end();
1009 : : }
1010 : :
1011 : 2 : void worksheet::remove_named_range(const std::string &name)
1012 : : {
1013 [ + + ]: 2 : if (!has_named_range(name))
1014 : : {
1015 [ + ]: 1 : throw key_not_found();
1016 : : }
1017 : :
1018 : 1 : d_->named_ranges_.erase(name);
1019 : 1 : }
1020 : :
1021 : 1 : void worksheet::reserve(std::size_t n)
1022 : : {
1023 : 1 : d_->cell_map_.reserve(n);
1024 : 1 : }
1025 : :
1026 : 21 : class header_footer worksheet::header_footer() const
1027 : : {
1028 : 21 : return d_->header_footer_.get();
1029 : : }
1030 : :
1031 : 1 : cell_reference worksheet::point_pos(int left, int top) const
1032 : : {
1033 [ + ]: 1 : column_t current_column = 1;
1034 : 1 : row_t current_row = 1;
1035 : :
1036 : 1 : double left_pos = 0;
1037 : 1 : double top_pos = 0;
1038 : :
1039 [ + + ]: 2 : while (left_pos <= left)
1040 : : {
1041 [ + + ]: 1 : left_pos += column_width(current_column++);
1042 : : }
1043 : :
1044 [ + + ]: 2 : while (top_pos <= top)
1045 : : {
1046 [ + ]: 1 : top_pos += row_height(current_row++);
1047 : : }
1048 : :
1049 [ + + + ]: 1 : return {current_column - 1, current_row - 1};
1050 : : }
1051 : :
1052 :UBC 0 : void worksheet::sheet_state(xlnt::sheet_state state)
1053 : : {
1054 [ # # ]: 0 : page_setup().sheet_state(state);
1055 : 0 : }
1056 : :
1057 :CBC 8 : sheet_state worksheet::sheet_state() const
1058 : : {
1059 [ + + ]: 8 : return page_setup().sheet_state();
1060 : : }
1061 : :
1062 : 92789 : void worksheet::add_column_properties(column_t column, const xlnt::column_properties &props)
1063 : : {
1064 : 92789 : d_->column_properties_[column] = props;
1065 : 92789 : }
1066 : :
1067 : 1482 : bool worksheet::has_column_properties(column_t column) const
1068 : : {
1069 [ + ]: 1482 : return d_->column_properties_.find(column) != d_->column_properties_.end();
1070 : : }
1071 : :
1072 : 1354 : column_properties &worksheet::column_properties(column_t column)
1073 : : {
1074 : 1354 : return d_->column_properties_[column];
1075 : : }
1076 : :
1077 :UBC 0 : const column_properties &worksheet::column_properties(column_t column) const
1078 : : {
1079 : 0 : return d_->column_properties_.at(column);
1080 : : }
1081 : :
1082 :CBC 1399 : row_properties &worksheet::row_properties(row_t row)
1083 : : {
1084 : 1399 : return d_->row_properties_[row];
1085 : : }
1086 : :
1087 : 14 : const row_properties &worksheet::row_properties(row_t row) const
1088 : : {
1089 : 14 : return d_->row_properties_.at(row);
1090 : : }
1091 : :
1092 : 15 : void worksheet::add_row_properties(row_t row, const xlnt::row_properties &props)
1093 : : {
1094 : 15 : d_->row_properties_[row] = props;
1095 : 15 : }
1096 : :
1097 : 3 : worksheet::iterator worksheet::begin()
1098 : : {
1099 [ + + ]: 3 : return rows().begin();
1100 : : }
1101 : :
1102 : 3 : worksheet::iterator worksheet::end()
1103 : : {
1104 [ + + ]: 3 : return rows().end();
1105 : : }
1106 : :
1107 : 2 : worksheet::const_iterator worksheet::cbegin() const
1108 : : {
1109 [ + + ]: 2 : return rows().cbegin();
1110 : : }
1111 : :
1112 : 2 : worksheet::const_iterator worksheet::cend() const
1113 : : {
1114 [ + + ]: 2 : return rows().cend();
1115 : : }
1116 : :
1117 : 2 : worksheet::const_iterator worksheet::begin() const
1118 : : {
1119 : 2 : return cbegin();
1120 : : }
1121 : :
1122 : 2 : worksheet::const_iterator worksheet::end() const
1123 : : {
1124 : 2 : return cend();
1125 : : }
1126 : :
1127 : 2 : void worksheet::print_title_rows(row_t start, row_t end)
1128 : : {
1129 : 2 : d_->print_title_rows_ = std::make_pair(start, end);
1130 : 2 : }
1131 : :
1132 : 10 : optional<std::pair<row_t, row_t>> worksheet::print_title_rows() const
1133 : : {
1134 : 10 : return d_->print_title_rows_;
1135 : : }
1136 : :
1137 : 2 : void worksheet::print_title_cols(column_t start, column_t end)
1138 : : {
1139 : 2 : d_->print_title_cols_ = std::make_pair(start, end);
1140 : 2 : }
1141 : :
1142 : 10 : optional<std::pair<column_t, column_t>> worksheet::print_title_cols() const
1143 : : {
1144 : 10 : return d_->print_title_cols_;
1145 : : }
1146 : :
1147 : 56 : bool worksheet::has_print_titles() const
1148 : : {
1149 [ + + + + ]: 56 : return d_->print_title_cols_.is_set() || d_->print_title_rows_.is_set();
1150 : : }
1151 : :
1152 :UBC 0 : void worksheet::clear_print_titles()
1153 : : {
1154 : 0 : d_->print_title_rows_.clear();
1155 : 0 : d_->print_title_cols_.clear();
1156 : 0 : }
1157 : :
1158 :CBC 2 : void worksheet::print_area(const std::string &print_area)
1159 : : {
1160 [ + + ]: 2 : d_->print_area_ = range_reference::make_absolute(range_reference(print_area));
1161 : 2 : }
1162 : :
1163 : 4 : range_reference worksheet::print_area() const
1164 : : {
1165 : 4 : return d_->print_area_.get();
1166 : : }
1167 : :
1168 : 56 : bool worksheet::has_print_area() const
1169 : : {
1170 : 56 : return d_->print_area_.is_set();
1171 : : }
1172 : :
1173 :UBC 0 : void worksheet::clear_print_area()
1174 : : {
1175 : 0 : return d_->print_area_.clear();
1176 : : }
1177 : :
1178 :CBC 76 : bool worksheet::has_view() const
1179 : : {
1180 : 76 : return !d_->views_.empty();
1181 : : }
1182 : :
1183 : 71 : sheet_view &worksheet::view(std::size_t index) const
1184 : : {
1185 : 71 : return d_->views_.at(index);
1186 : : }
1187 : :
1188 : 258 : void worksheet::add_view(const sheet_view &new_view)
1189 : : {
1190 : 258 : d_->views_.push_back(new_view);
1191 : 258 : }
1192 : :
1193 : 34 : void worksheet::register_comments_in_manifest()
1194 : : {
1195 [ + + ]: 34 : workbook().register_worksheet_part(*this, relationship_type::comments);
1196 : 34 : }
1197 : :
1198 : 16 : void worksheet::register_calc_chain_in_manifest()
1199 : : {
1200 [ + + ]: 16 : workbook().register_workbook_part(relationship_type::calculation_chain);
1201 : 16 : }
1202 : :
1203 : 53 : bool worksheet::has_phonetic_properties() const
1204 : : {
1205 : 53 : return d_->phonetic_properties_.is_set();
1206 : : }
1207 : :
1208 : 4 : const phonetic_pr &worksheet::phonetic_properties() const
1209 : : {
1210 : 4 : return d_->phonetic_properties_.get();
1211 : : }
1212 : :
1213 :UBC 0 : void worksheet::phonetic_properties(const phonetic_pr &phonetic_props)
1214 : : {
1215 : 0 : d_->phonetic_properties_.set(phonetic_props);
1216 : 0 : }
1217 : :
1218 :CBC 54 : bool worksheet::has_header_footer() const
1219 : : {
1220 : 54 : return d_->header_footer_.is_set();
1221 : : }
1222 : :
1223 : 29 : void worksheet::header_footer(const class header_footer &hf)
1224 : : {
1225 : 29 : d_->header_footer_ = hf;
1226 : 29 : }
1227 : :
1228 :UBC 0 : void worksheet::clear_page_breaks()
1229 : : {
1230 : 0 : d_->row_breaks_.clear();
1231 : 0 : d_->column_breaks_.clear();
1232 : 0 : }
1233 : :
1234 : 0 : void worksheet::page_break_at_row(row_t row)
1235 : : {
1236 : 0 : d_->row_breaks_.push_back(row);
1237 : 0 : }
1238 : :
1239 :CBC 53 : const std::vector<row_t> &worksheet::page_break_rows() const
1240 : : {
1241 : 53 : return d_->row_breaks_;
1242 : : }
1243 : :
1244 :UBC 0 : void worksheet::page_break_at_column(xlnt::column_t column)
1245 : : {
1246 : 0 : d_->column_breaks_.push_back(column);
1247 : 0 : }
1248 : :
1249 :CBC 53 : const std::vector<column_t> &worksheet::page_break_columns() const
1250 : : {
1251 : 53 : return d_->column_breaks_;
1252 : : }
1253 : :
1254 : 35 : double worksheet::column_width(column_t column) const
1255 : : {
1256 : : static const auto DefaultColumnWidth = 51.85;
1257 : :
1258 [ - + ]: 35 : if (has_column_properties(column))
1259 : : {
1260 :UBC 0 : return column_properties(column).width.get();
1261 : : }
1262 : : else
1263 : : {
1264 :CBC 35 : return points_to_pixels(DefaultColumnWidth, 96.0);
1265 : : }
1266 : : }
1267 : :
1268 : 17 : double worksheet::row_height(row_t row) const
1269 : : {
1270 : : static const auto DefaultRowHeight = 15.0;
1271 : :
1272 [ + + - + : 17 : if (has_row_properties(row) && row_properties(row).height.is_set())
- + ]
1273 : : {
1274 :UBC 0 : return row_properties(row).height.get();
1275 : : }
1276 : : else
1277 : : {
1278 :CBC 17 : return points_to_pixels(DefaultRowHeight, 96.0);
1279 : : }
1280 : : }
1281 : :
1282 : 18 : void worksheet::garbage_collect_formulae()
1283 : : {
1284 [ + + ]: 18 : workbook().garbage_collect_formulae();
1285 : 18 : }
1286 : :
1287 : 2 : void worksheet::parent(xlnt::workbook &wb)
1288 : : {
1289 : 2 : d_->parent_ = wb.d_;
1290 : 2 : }
1291 : :
1292 : 1 : conditional_format worksheet::conditional_format(const range_reference &ref, const condition &when)
1293 : : {
1294 [ + + + ]: 1 : return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
1295 : : }
1296 : :
1297 : 51 : path worksheet::path() const
1298 : : {
1299 [ + ]: 51 : auto rel = referring_relationship();
1300 [ + + + + : 102 : return xlnt::path(rel.source().path().parent().append(rel.target().path()));
+ + ]
1301 : 51 : }
1302 : :
1303 : 53 : relationship worksheet::referring_relationship() const
1304 : : {
1305 [ + ]: 53 : auto wb = workbook();
1306 [ + ]: 53 : auto &manifest = wb.manifest();
1307 [ + + ]: 106 : auto wb_rel = manifest.relationship(xlnt::path("/"),
1308 [ + ]: 53 : relationship_type::office_document);
1309 : 106 : auto ws_rel = manifest.relationship(wb_rel.target().path(),
1310 [ + + + + : 53 : workbook().d_->sheet_title_rel_id_map_.at(title()));
+ + ]
1311 : 53 : return ws_rel;
1312 : 53 : }
1313 : :
1314 : 53 : sheet_format_properties worksheet::format_properties() const
1315 : : {
1316 : 53 : return d_->format_properties_;
1317 : : }
1318 : :
1319 : 3 : void worksheet::format_properties(const sheet_format_properties &properties)
1320 : : {
1321 : 3 : d_->format_properties_ = properties;
1322 : 3 : }
1323 : :
1324 : 3 : bool worksheet::has_drawing() const
1325 : : {
1326 : 3 : return d_->drawing_.is_set();
1327 : : }
1328 : :
1329 :UBC 0 : bool worksheet::is_empty() const
1330 : : {
1331 : 0 : return d_->cell_map_.empty();
1332 : : }
1333 : :
1334 :CBC 5 : int worksheet::zoom_scale() const
1335 : : {
1336 [ + + ]: 5 : if (!has_view())
1337 : : {
1338 : 1 : return 100;
1339 : : }
1340 : :
1341 : 4 : return view(0).zoom_scale();
1342 : : }
1343 : :
1344 : 2 : void worksheet::zoom_scale(int scale)
1345 : : {
1346 [ + + ]: 2 : if (!has_view())
1347 : : {
1348 : 1 : sheet_view sv;
1349 [ + ]: 1 : add_view(sv);
1350 : 1 : }
1351 : 2 : view(0).zoom_scale(scale);
1352 : 2 : }
1353 : :
1354 : : } // namespace xlnt
|