• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xlnt-community / xlnt / 8d79d0ed-2f48-4ded-be7b-965c1cf2ef49

27 Jan 2026 07:07AM UTC coverage: 83.928% (+1.1%) from 82.793%
8d79d0ed-2f48-4ded-be7b-965c1cf2ef49

Pull #87

circleci

doomlaur
Fixed typo in README.md
Pull Request #87: Improve documentation when exceptions are thrown (fixes #81)

15263 of 19954 branches covered (76.49%)

722 of 901 new or added lines in 37 files covered. (80.13%)

15 existing lines in 5 files now uncovered.

12491 of 14883 relevant lines covered (83.93%)

12216.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.49
./source/worksheet/worksheet.cpp
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
int points_to_pixels(double points, double dpi)
52✔
58
{
59
    return static_cast<int>(std::ceil(points * dpi / 72));
52✔
60
}
61

62
} // namespace
63

64
namespace xlnt {
65

66
worksheet::worksheet()
6✔
67
    : d_(nullptr)
6✔
68
{
69
}
6✔
70

71
worksheet::worksheet(detail::worksheet_impl *d)
3,648✔
72
    : d_(d)
3,648✔
73
{
74
}
3,648✔
75

76
worksheet::worksheet(const worksheet &rhs)
4,580✔
77
    : d_(rhs.d_)
4,580✔
78
{
79
}
4,580✔
80

81
bool worksheet::has_frozen_panes() const
8✔
82
{
83
    return !d_->views_.empty() && d_->views_.front().has_pane()
16✔
84
        && (d_->views_.front().pane().state == pane_state::frozen
16!
85
            || d_->views_.front().pane().state == pane_state::frozen_split);
8!
86
}
87

88
void worksheet::create_named_range(const std::string &name, const std::string &reference_string)
6✔
89
{
90
    create_named_range(name, range_reference(reference_string));
6✔
91
}
4✔
92

93
void worksheet::create_named_range(const std::string &name, const range_reference &reference)
13✔
94
{
95
    try
96
    {
97
        auto temp = cell_reference::split_reference(name);
13✔
98

99
        // Citing the OOXML specification:
100
        // In SpreadsheetML, cell references range from column A1–A1048576 (column A:A) to column XFD1–XFD1048576 (column XFD:XFD).
101
        // An implementation can extend this range. However, to avoid ambiguities, it is necessary to ensure
102
        // that defined names are distinct from cell references, or that one takes precedence over the other.
103
        // With this in mind, the following rules apply:
104
        // 1. A producer or consumer shall consider a defined name of the form used by cells in the range A1–XFD1048576 to be an error.
105
        // 2. All other names outside this range can be defined names and shall override a cell reference if an ambiguity exists.
106
        if (column_t(temp.first) <= xlnt::constants::max_column_reference_default() && temp.second <= xlnt::constants::max_row_reference_default())
4✔
107
        {
108
            throw invalid_parameter("named range \"" + name + "\" uses a forbidden name (inside the valid cell reference range A1 - XFD1048576, which is not allowed)");
2✔
109
        }
110
    }
4✔
111
    catch (xlnt::invalid_cell_reference &)
11✔
112
    {
113
        // name is not a valid reference, that's good
114
    }
9✔
115

116
    std::vector<named_range::target> targets;
11✔
117
    targets.push_back({*this, reference});
11✔
118

119
    d_->named_ranges_[name] = xlnt::named_range(name, targets);
11✔
120
}
11✔
121

122
cell worksheet::operator[](const cell_reference &ref)
108✔
123
{
124
    return cell(ref);
108✔
125
}
126

127
std::vector<range_reference> worksheet::merged_ranges() const
63✔
128
{
129
    return d_->merged_cells_;
63✔
130
}
131

132
bool worksheet::has_page_margins() const
56✔
133
{
134
    return d_->page_margins_.is_set();
56✔
135
}
136

137
bool worksheet::has_page_setup() const
174✔
138
{
139
    return d_->page_setup_.is_set();
174✔
140
}
141

142
page_margins worksheet::page_margins() const
290✔
143
{
144
    if (!d_->page_margins_.is_set())
290✔
145
    {
146
        throw xlnt::invalid_attribute("worksheet \"" + d_->title_ + "\" has no page margins");
1✔
147
    }
148
    return d_->page_margins_.get();
289✔
149
}
150

151
void worksheet::page_margins(const class page_margins &margins)
450✔
152
{
153
    d_->page_margins_ = margins;
450✔
154
}
450✔
155

156
void worksheet::clear_page_margins()
1✔
157
{
158
    d_->page_margins_.clear();
1✔
159
}
1✔
160

161
void worksheet::auto_filter(const std::string &reference_string)
1✔
162
{
163
    auto_filter(range_reference(reference_string));
1✔
164
}
1✔
165

166
void worksheet::auto_filter(const range_reference &reference)
2✔
167
{
168
    d_->auto_filter_ = reference;
2✔
169
}
2✔
170

171
void worksheet::auto_filter(const xlnt::range &range)
×
172
{
173
    auto_filter(range.reference());
×
174
}
×
175

176
range_reference worksheet::auto_filter() const
5✔
177
{
178
    if (!d_->auto_filter_.is_set())
5✔
179
    {
180
        throw xlnt::invalid_attribute("worksheet \"" + d_->title_ + "\" has no auto-filter");
2✔
181
    }
182
    return d_->auto_filter_.get();
3✔
183
}
184

185
bool worksheet::has_auto_filter() const
111✔
186
{
187
    return d_->auto_filter_.is_set();
111✔
188
}
189

190
void worksheet::clear_auto_filter()
×
191
{
192
    d_->auto_filter_.clear();
×
193
}
×
194

195
void worksheet::page_setup(const struct page_setup &setup)
36✔
196
{
197
    d_->page_setup_ = setup;
36✔
198
}
36✔
199

200
page_setup worksheet::page_setup() const
73✔
201
{
202
    if (d_->page_setup_.is_set())
73✔
203
    {
204
        return d_->page_setup_.get();
72✔
205
    }
206
    return {};
1✔
207
}
208

209
workbook worksheet::workbook()
699✔
210
{
211
    return d_->parent_;
699✔
212
}
213

214
const workbook worksheet::workbook() const
358✔
215
{
216
    return d_->parent_;
358✔
217
}
218

219
void worksheet::garbage_collect()
1✔
220
{
221
    auto cell_iter = d_->cell_map_.begin();
1✔
222

223
    while (cell_iter != d_->cell_map_.end())
2✔
224
    {
225
        if (xlnt::cell(&cell_iter->second).garbage_collectible())
1!
226
        {
227
            cell_iter = d_->cell_map_.erase(cell_iter);
×
228
        }
229
        else
230
        {
231
            ++cell_iter;
1✔
232
        }
233
    }
234
}
1✔
235

236
void worksheet::id(std::size_t id)
×
237
{
238
    d_->id_ = id;
×
239
}
×
240

241
std::size_t worksheet::id() const
293✔
242
{
243
    return d_->id_;
293✔
244
}
245

246
std::string worksheet::title() const
1,509✔
247
{
248
    return d_->title_;
1,509✔
249
}
250

251
void worksheet::title(const std::string &title)
37✔
252
{
253
    // do no work if we don't need to
254
    if (d_->title_ == title)
37✔
255
    {
256
        return;
6✔
257
    }
258

259
    try
260
    {
261
        // excel limits worksheet titles to 31 Unicode characters
262
        if (title.empty() || detail::string_length(title) > 31)
31✔
263
        {
264
            throw invalid_sheet_title(title);
2✔
265
        }
266
    }
267
    catch (const xlnt::encoding_error& ex)
3✔
268
    {
269
        throw invalid_sheet_title(title);
1✔
270
    }
1✔
271

272
    // invalid characters in a worksheet name
273
    if (title.find_first_of("*:/\\?[]") != std::string::npos)
28✔
274
    {
275
        throw invalid_sheet_title(title);
7✔
276
    }
277
    // try and insert the new name into the worksheets map
278
    // if the insert fails, we have a duplicate sheet name
279
    auto insert_result = workbook().d_->sheet_title_rel_id_map_.insert(
42✔
280
        std::make_pair(title, workbook().d_->sheet_title_rel_id_map_[d_->title_]));
42✔
281
    if (!insert_result.second) // insert failed, duplication detected
21✔
282
    {
283
        throw invalid_sheet_title(title);
2✔
284
    }
285
    // if the insert succeeded (i.e. wasn't a duplicate sheet name)
286
    // update the worksheet title and remove the old relation
287
    workbook().d_->sheet_title_rel_id_map_.erase(d_->title_);
19✔
288
    d_->title_ = title;
19✔
289

290
    workbook().update_sheet_properties();
19✔
291
}
292

293
cell_reference worksheet::frozen_panes() const
4✔
294
{
295
    if (!has_frozen_panes())
4✔
296
    {
297
        throw xlnt::invalid_attribute("worksheet \"" + d_->title_ + "\" has no frozen panes");
2✔
298
    }
299

300
    return d_->views_.front().pane().top_left_cell.get();
2✔
301
}
302

303
void worksheet::freeze_panes(xlnt::cell top_left_cell)
2✔
304
{
305
    freeze_panes(top_left_cell.reference());
2✔
306
}
2✔
307

308
void worksheet::freeze_panes(const cell_reference &ref)
7✔
309
{
310
    if (ref == "A1")
7✔
311
    {
312
        unfreeze_panes();
1✔
313
        return;
1✔
314
    }
315
    if (!has_view())
6!
316
    {
317
        d_->views_.push_back(sheet_view());
×
318
    }
319

320
    auto &primary_view = d_->views_.front();
6✔
321
    if (!primary_view.has_pane())
6!
322
    {
323
        primary_view.pane(pane());
6✔
324
    }
325

326
    primary_view.pane().top_left_cell = ref;
6✔
327
    primary_view.pane().state = pane_state::frozen;
6✔
328

329
    primary_view.clear_selections();
6✔
330
    if (ref.column() == "A") // no column is frozen
6✔
331
    {
332
        primary_view.add_selection(selection(pane_corner::bottom_left, ref));
1✔
333
        primary_view.pane().active_pane = pane_corner::bottom_left;
1✔
334
        primary_view.pane().y_split = ref.row() - 1;
1✔
335
    }
336
    else if (ref.row() == 1) // no row is frozen
5✔
337
    {
338
        primary_view.add_selection(selection(pane_corner::top_right, ref));
1✔
339
        primary_view.pane().active_pane = pane_corner::top_right;
1✔
340
        primary_view.pane().x_split = ref.column_index() - 1;
1✔
341
    }
342
    else // column and row is frozen
343
    {
344
        primary_view.add_selection(selection(pane_corner::top_right, cell_reference(ref.column(), 1)));
4✔
345
        primary_view.add_selection(selection(pane_corner::bottom_left, cell_reference(1, ref.row())));
4✔
346
        primary_view.add_selection(selection(pane_corner::bottom_right, ref));
4✔
347
        primary_view.pane().active_pane = pane_corner::bottom_right;
4✔
348
        primary_view.pane().x_split = ref.column_index() - 1;
4✔
349
        primary_view.pane().y_split = ref.row() - 1;
4✔
350
    }
351
}
352

353
void worksheet::unfreeze_panes()
2✔
354
{
355
    if (!has_view()) return;
2!
356

357
    auto &primary_view = d_->views_.front();
2✔
358

359
    primary_view.clear_selections();
2✔
360
    primary_view.clear_pane();
2✔
361
}
362

363
void worksheet::active_cell(const cell_reference &ref)
1✔
364
{
365
    if (!has_view())
1!
366
    {
367
        d_->views_.push_back(sheet_view());
×
368
    }
369

370
    auto &primary_view = d_->views_.front();
1✔
371

372
    if (!primary_view.has_selections())
1!
373
    {
374
        primary_view.add_selection(selection(pane_corner::bottom_right, ref));
1✔
375
    }
376
    else
377
    {
378
        primary_view.selection(0).active_cell(ref);
×
379
    }
380
}
1✔
381

382
bool worksheet::has_active_cell() const
3✔
383
{
384
    if (!has_view()) return false;
3!
385
    auto &primary_view = d_->views_.front();
3✔
386
    if (!primary_view.has_selections()) return false;
3✔
387
    auto primary_selection = primary_view.selection(0);
2✔
388

389
    return primary_selection.has_active_cell();
2✔
390
}
2✔
391

392
cell_reference worksheet::active_cell() const
3✔
393
{
394
    if (!has_view())
3!
395
    {
NEW
396
        throw xlnt::invalid_attribute("Worksheet \"" + d_->title_ + "\" has no view.");
×
397
    }
398

399
    auto &primary_view = d_->views_.front();
3✔
400

401
    if (!primary_view.has_selections())
3✔
402
    {
403
        throw xlnt::invalid_attribute("Default worksheet view of worksheet \"" + d_->title_ + "\" has no selections.");
1✔
404
    }
405

406
    return primary_view.selection(0).active_cell();
2✔
407
}
408

409
cell worksheet::cell(const cell_reference &reference)
3,028✔
410
{
411
    auto match = d_->cell_map_.find(reference);
3,028✔
412
    if (match == d_->cell_map_.end())
3,028✔
413
    {
414
        auto impl = detail::cell_impl();
1,147✔
415
        impl.parent_ = d_;
1,147✔
416
        impl.column_ = reference.column_index();
1,147✔
417
        impl.row_ = reference.row();
1,147✔
418

419
        match = d_->cell_map_.emplace(reference, impl).first;
1,147✔
420
    }
1,147✔
421
    return xlnt::cell(&match->second);
3,028✔
422
}
423

424
const cell worksheet::cell(const cell_reference &reference) const
48✔
425
{
426
    const auto match = d_->cell_map_.find(reference);
48✔
427
    if (match == d_->cell_map_.end())
48✔
428
    {
429
        throw xlnt::invalid_parameter("Requested cell " + reference.to_string() + " doesn't exist.");
9✔
430
    }
431
    return xlnt::cell(&match->second);
39✔
432
}
433

434
cell worksheet::cell(xlnt::column_t column, row_t row)
23✔
435
{
436
    return cell(cell_reference(column, row));
23✔
437
}
438

439
const cell worksheet::cell(xlnt::column_t column, row_t row) const
1✔
440
{
441
    return cell(cell_reference(column, row));
1!
442
}
443

444
bool worksheet::has_cell(const cell_reference &reference) const
4,167✔
445
{
446
    const auto cell = d_->cell_map_.find(reference);
4,167✔
447
    return cell != d_->cell_map_.cend();
4,167✔
448
}
449

450
bool worksheet::has_row_properties(row_t row) const
2,802✔
451
{
452
    return d_->row_properties_.find(row) != d_->row_properties_.end();
2,802✔
453
}
454

455
range worksheet::named_range(const std::string &name)
9✔
456
{
457
    auto named_range = d_->named_ranges_.find(name);
9✔
458

459
    if (named_range == d_->named_ranges_.end())
9✔
460
    {
461
        throw key_not_found(name);
2✔
462
    }
463

464
    return range(named_range->second.targets()[0].second);
14✔
465
}
466

467
const range worksheet::named_range(const std::string &name) const
3✔
468
{
469
    auto named_range = d_->named_ranges_.find(name);
3✔
470

471
    if (named_range == d_->named_ranges_.end())
3✔
472
    {
473
        throw key_not_found(name);
2✔
474
    }
475

476
    return range(named_range->second.targets()[0].second);
2✔
477
}
478

479
column_t worksheet::lowest_column() const
59✔
480
{
481
    if (d_->cell_map_.empty())
59✔
482
    {
483
        return constants::min_column();
20✔
484
    }
485

486
    auto lowest = constants::max_column();
39✔
487

488
    for (auto &cell : d_->cell_map_)
1,041✔
489
    {
490
        lowest = std::min(lowest, cell.first.column());
1,002✔
491
    }
492

493
    return lowest;
39✔
494
}
495

496
column_t worksheet::lowest_column_or_props() const
55✔
497
{
498
    auto lowest = lowest_column();
55✔
499

500
    if (d_->cell_map_.empty() && !d_->column_properties_.empty())
55✔
501
    {
502
        lowest = d_->column_properties_.begin()->first;
1✔
503
    }
504

505
    for (auto &props : d_->column_properties_)
1,389✔
506
    {
507
        lowest = std::min(lowest, props.first);
1,334✔
508
    }
509

510
    return lowest;
55✔
511
}
512

513
row_t worksheet::lowest_row() const
82✔
514
{
515
    if (d_->cell_map_.empty())
82✔
516
    {
517
        return constants::min_row();
34✔
518
    }
519

520
    auto lowest = constants::max_row();
48✔
521

522
    for (auto &cell : d_->cell_map_)
1,269✔
523
    {
524
        lowest = std::min(lowest, cell.first.row());
1,221✔
525
    }
526

527
    return lowest;
48✔
528
}
529

530
row_t worksheet::lowest_row_or_props() const
55✔
531
{
532
    auto lowest = lowest_row();
55✔
533

534
    if (d_->cell_map_.empty() && !d_->row_properties_.empty())
55✔
535
    {
536
        lowest = d_->row_properties_.begin()->first;
1✔
537
    }
538

539
    for (auto &props : d_->row_properties_)
1,353✔
540
    {
541
        lowest = std::min(lowest, props.first);
1,298✔
542
    }
543

544
    return lowest;
55✔
545
}
546

547
row_t worksheet::highest_row() const
88✔
548
{
549
    auto highest = constants::min_row();
88✔
550

551
    for (auto &cell : d_->cell_map_)
1,899✔
552
    {
553
        highest = std::max(highest, cell.first.row());
1,811✔
554
    }
555

556
    return highest;
88✔
557
}
558

559
row_t worksheet::highest_row_or_props() const
55✔
560
{
561
    auto highest = highest_row();
55✔
562

563
    if (d_->cell_map_.empty() && !d_->row_properties_.empty())
55✔
564
    {
565
        highest = d_->row_properties_.begin()->first;
1✔
566
    }
567

568
    for (auto &props : d_->row_properties_)
1,353✔
569
    {
570
        highest = std::max(highest, props.first);
1,298✔
571
    }
572

573
    return highest;
55✔
574
}
575

576
column_t worksheet::highest_column() const
60✔
577
{
578
    auto highest = constants::min_column();
60✔
579

580
    for (auto &cell : d_->cell_map_)
1,063✔
581
    {
582
        highest = std::max(highest, cell.first.column());
1,003✔
583
    }
584

585
    return highest;
60✔
586
}
587

588
column_t worksheet::highest_column_or_props() const
55✔
589
{
590
    auto highest = highest_column();
55✔
591

592
    if (d_->cell_map_.empty() && !d_->column_properties_.empty())
55✔
593
    {
594
        highest = d_->column_properties_.begin()->first;
1✔
595
    }
596

597
    for (auto &props : d_->column_properties_)
1,389✔
598
    {
599
        highest = std::max(highest, props.first);
1,334✔
600
    }
601

602
    return highest;
55✔
603
}
604

605
range_reference worksheet::calculate_dimension(bool skip_null, bool skip_row_props) const
173✔
606
{
607
    // partially optimised version of:
608
    // return range_reference(lowest_column(), lowest_row_or_props(),
609
    //                        highest_column(), highest_row_or_props());
610
    //
611
    if (d_->cell_map_.empty() && d_->row_properties_.empty())
173!
612
    {
613
        return range_reference(constants::min_column(), constants::min_row(),
614
            constants::min_column(), constants::min_row());
32✔
615
    }
616

617
    // if skip_null = false, min row = min_row() and min column = min_column()
618
    // in order to include first empty rows and columns
619
    row_t min_row_prop = skip_null? constants::max_row() : constants::min_row();
141✔
620
    row_t max_row_prop = constants::min_row();
141✔
621
    if (!skip_row_props)
141✔
622
    {
623
        for (const auto &row_prop : d_->row_properties_)
2,869✔
624
        {
625
            if(skip_null){
2,774✔
626
                min_row_prop = std::min(min_row_prop, row_prop.first);
2,772✔
627
            }
628
            max_row_prop = std::max(max_row_prop, row_prop.first);
2,774✔
629
        }
630
    }
631
    if (d_->cell_map_.empty())
141!
632
    {
633
        return range_reference(constants::min_column(), min_row_prop,
634
            constants::min_column(), max_row_prop);
×
635
    }
636
    // find min and max row/column in cell map
637
    column_t min_col = skip_null? constants::max_column() : constants::min_column();
141✔
638
    column_t max_col = constants::min_column();
141✔
639
    row_t min_row = min_row_prop;
141✔
640
    row_t max_row = max_row_prop;
141✔
641
    for (auto &c : d_->cell_map_)
3,458✔
642
    {
643
        if(skip_null){
3,317✔
644
            min_col = std::min(min_col, c.second.column_);
3,284✔
645
            min_row = std::min(min_row, c.second.row_);
3,284✔
646
        }
647
        max_col = std::max(max_col, c.second.column_);
3,317✔
648
        max_row = std::max(max_row, c.second.row_);
3,317✔
649
    }
650
    return range_reference(min_col, min_row, max_col, max_row);
141✔
651
}
652

653
range worksheet::range(const std::string &reference_string)
32✔
654
{
655
    if (has_named_range(reference_string))
32✔
656
    {
657
        return named_range(reference_string);
3✔
658
    }
659

660
    return range(range_reference(reference_string));
29✔
661
}
662

663
const range worksheet::range(const std::string &reference_string) const
1✔
664
{
665
    if (has_named_range(reference_string))
1!
666
    {
667
        return named_range(reference_string);
×
668
    }
669

670
    return range(range_reference(reference_string));
1✔
671
}
672

673
range worksheet::range(const range_reference &reference)
49✔
674
{
675
    return xlnt::range(*this, reference);
49✔
676
}
677

678
const range worksheet::range(const range_reference &reference) const
2✔
679
{
680
    return xlnt::range(*this, reference);
2✔
681
}
682

683
void worksheet::merge_cells(const std::string &reference_string)
9✔
684
{
685
    merge_cells(range_reference(reference_string));
9✔
686
}
9✔
687

688
void worksheet::unmerge_cells(const std::string &reference_string)
2✔
689
{
690
    unmerge_cells(range_reference(reference_string));
2✔
691
}
1✔
692

693
void worksheet::merge_cells(const range_reference &reference)
11✔
694
{
695
    d_->merged_cells_.push_back(reference);
11✔
696
    bool first = true;
11✔
697

698
    for (auto row : range(reference))
149✔
699
    {
700
        for (auto cell : row)
827✔
701
        {
702
            cell.merged(true);
758✔
703

704
            if (!first)
758✔
705
            {
706
                if (cell.data_type() == cell::type::shared_string)
747✔
707
                {
708
                    cell.value("");
1✔
709
                }
710
                else
711
                {
712
                    cell.clear_value();
746✔
713
                }
714
            }
715

716
            first = false;
758✔
717
        }
718
    }
11✔
719
}
11✔
720

721
void worksheet::unmerge_cells(const range_reference &reference)
3✔
722
{
723
    auto match = std::find(d_->merged_cells_.begin(), d_->merged_cells_.end(), reference);
3✔
724

725
    if (match == d_->merged_cells_.end())
3✔
726
    {
727
        throw invalid_parameter("cell " + reference.to_string() + " has not been merged, so it cannot be unmerged");
2✔
728
    }
729

730
    d_->merged_cells_.erase(match);
1✔
731

732
    for (auto row : range(reference))
9✔
733
    {
734
        for (auto cell : row)
36✔
735
        {
736
            cell.merged(false);
16✔
737
        }
738
    }
1✔
739
}
1✔
740

741
row_t worksheet::next_row() const
×
742
{
743
    auto row = highest_row() + 1;
×
744

745
    if (row == 2 && d_->cell_map_.size() == 0)
×
746
    {
747
        row = 1;
×
748
    }
749

750
    return row;
×
751
}
752

753
xlnt::range worksheet::rows(bool skip_null)
41✔
754
{
755
    return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::row, skip_null);
41✔
756
}
757

758
const xlnt::range worksheet::rows(bool skip_null) const
8✔
759
{
760
    return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::row, skip_null);
8✔
761
}
762

763
xlnt::range worksheet::columns(bool skip_null)
16✔
764
{
765
    return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::column, skip_null);
16✔
766
}
767

768
const xlnt::range worksheet::columns(bool skip_null) const
2✔
769
{
770
    return xlnt::range(*this, calculate_dimension(skip_null, skip_null), major_order::column, skip_null);
2✔
771
}
772

773
/*
774
//TODO: finish implementing cell_iterator wrapping before uncommenting
775

776
cell_vector worksheet::cells(bool skip_null)
777
{
778
    const auto dimension = calculate_dimension();
779
    return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
780
}
781

782
const cell_vector worksheet::cells(bool skip_null) const
783
{
784
    const auto dimension = calculate_dimension();
785
    return cell_vector(*this, dimension.top_left(), dimension, major_order::row, skip_null, true);
786
}
787
*/
788

789
void worksheet::clear_cell(const cell_reference &ref)
7✔
790
{
791
    d_->cell_map_.erase(ref);
7✔
792
    // TODO: garbage collect newly unreferenced resources such as styles?
793
}
7✔
794

795
void worksheet::clear_row(row_t row)
1✔
796
{
797
    for (auto it = d_->cell_map_.begin(); it != d_->cell_map_.end();)
149✔
798
    {
799
        if (it->first.row() == row)
148✔
800
        {
801
            it = d_->cell_map_.erase(it);
4✔
802
        }
803
        else
804
        {
805
            ++it;
144✔
806
        }
807
    }
808
    d_->row_properties_.erase(row);
1✔
809
    // TODO: garbage collect newly unreferenced resources such as styles?
810
}
1✔
811

812
void worksheet::insert_rows(row_t row, std::uint32_t amount)
3✔
813
{
814
    move_cells(row, amount, row_or_col_t::row);
3✔
815
}
2✔
816

817
void worksheet::insert_columns(column_t column, std::uint32_t amount)
3✔
818
{
819
    move_cells(column.index, amount, row_or_col_t::column);
3✔
820
}
2✔
821

822
void worksheet::delete_rows(row_t row, std::uint32_t amount)
7✔
823
{
824
    move_cells(row + amount, amount, row_or_col_t::row, true);
7✔
825
}
6✔
826

827
void worksheet::delete_columns(column_t column, std::uint32_t amount)
3✔
828
{
829
    move_cells(column.index + amount, amount, row_or_col_t::column, true);
3✔
830
}
2✔
831

832
void worksheet::move_cells(std::uint32_t min_index, std::uint32_t amount, row_or_col_t row_or_col, bool reverse)
16✔
833
{
834
    if (reverse && amount > min_index)
16✔
835
    {
836
        throw xlnt::invalid_parameter("Cannot move cells before the minimum index");
6✔
837
    }
838

839
    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))
14✔
840
    {
841
        throw xlnt::invalid_parameter("Cannot move cells as they would be outside the maximum bounds of the spreadsheet");
6✔
842
    }
843

844
    std::vector<detail::cell_impl> cells_to_move;
12✔
845

846
    auto cell_iter = d_->cell_map_.cbegin();
12✔
847
    while (cell_iter != d_->cell_map_.cend())
107✔
848
    {
849
        std::uint32_t current_index;
850
        switch (row_or_col)
95!
851
        {
852
        case row_or_col_t::row:
51✔
853
            current_index = cell_iter->first.row();
51✔
854
            break;
51✔
855
        case row_or_col_t::column:
44✔
856
            current_index = cell_iter->first.column().index;
44✔
857
            break;
44✔
858
        default:
×
NEW
859
            throw xlnt::unhandled_switch_case(static_cast<long long>(row_or_col));
×
860
        }
861

862
        if (current_index >= min_index) // extract cells to be moved
95✔
863
        {
864
            auto cell = cell_iter->second;
42✔
865
            if (row_or_col == row_or_col_t::row)
42✔
866
            {
867
                cell.row_ = reverse ? cell.row_ - amount : cell.row_ + amount;
26✔
868
            }
869
            else if (row_or_col == row_or_col_t::column)
16!
870
            {
871
                cell.column_ = reverse ? cell.column_.index - amount : cell.column_.index + amount;
16✔
872
            }
873

874
            cells_to_move.push_back(cell);
42✔
875
            cell_iter = d_->cell_map_.erase(cell_iter);
42✔
876
        }
42✔
877
        else if (reverse && current_index >= min_index - amount) // delete destination cells
53✔
878
        {
879
            cell_iter = d_->cell_map_.erase(cell_iter);
21✔
880
        }
881
        else // skip other cells
882
        {
883
            ++cell_iter;
32✔
884
        }
885
    }
886

887
    for (auto &cell : cells_to_move)
54✔
888
    {
889
        d_->cell_map_[cell_reference(cell.column_, cell.row_)] = cell;
42✔
890
    }
891

892
    if (row_or_col == row_or_col_t::row)
12✔
893
    {
894
        std::vector<std::pair<row_t, xlnt::row_properties>> properties_to_move;
8✔
895

896
        auto row_prop_iter = d_->row_properties_.cbegin();
8✔
897
        while (row_prop_iter != d_->row_properties_.cend())
16✔
898
        {
899
            auto current_row = row_prop_iter->first;
8✔
900
            if (current_row >= min_index) // extract properties that need to be moved
8✔
901
            {
902
                auto tmp_row = reverse ? current_row - amount : current_row + amount;
3✔
903
                properties_to_move.push_back({tmp_row, row_prop_iter->second});
3✔
904
                row_prop_iter = d_->row_properties_.erase(row_prop_iter);
3✔
905
            }
906
            else if (reverse && current_row >= min_index - amount) // clear properties of destination when in reverse
5✔
907
            {
908
                row_prop_iter = d_->row_properties_.erase(row_prop_iter);
3✔
909
            }
910
            else // skip the rest
911
            {
912
                ++row_prop_iter;
2✔
913
            }
914
        }
915

916
        for (const auto &prop : properties_to_move)
11✔
917
        {
918
            add_row_properties(prop.first, prop.second);
3✔
919
        }
920
    }
8✔
921
    else if (row_or_col == row_or_col_t::column)
4!
922
    {
923
        std::vector<std::pair<column_t, xlnt::column_properties>> properties_to_move;
4✔
924

925
        auto col_prop_iter = d_->column_properties_.cbegin();
4✔
926
        while (col_prop_iter != d_->column_properties_.cend())
10✔
927
        {
928
            auto current_col = col_prop_iter->first.index;
6✔
929
            if (current_col >= min_index) // extract properties that need to be moved
6✔
930
            {
931
                auto tmp_column = column_t(reverse ? current_col - amount : current_col + amount);
2✔
932
                properties_to_move.push_back({tmp_column, col_prop_iter->second});
2✔
933
                col_prop_iter = d_->column_properties_.erase(col_prop_iter);
2✔
934
            }
935
            else if (reverse && current_col >= min_index - amount) // clear properties of destination when in reverse
4✔
936
            {
937
                col_prop_iter = d_->column_properties_.erase(col_prop_iter);
2✔
938
            }
939
            else // skip the rest
940
            {
941
                ++col_prop_iter;
2✔
942
            }
943
        }
944

945
        for (auto &prop : properties_to_move)
6✔
946
        {
947
            add_column_properties(prop.first, prop.second);
2✔
948
        }
949
    }
4✔
950

951
    // adjust merged cells
952
    auto shift_reference = [min_index, amount, row_or_col, reverse](cell_reference &ref) {
48✔
953
        auto index = row_or_col == row_or_col_t::row ? ref.row() : ref.column_index();
48✔
954
        if (index >= min_index)
48✔
955
        {
956
            auto new_index = reverse ? index - amount : index + amount;
28✔
957
            if (row_or_col == row_or_col_t::row)
28✔
958
            {
959
                ref.row(new_index);
18✔
960
            }
961
            else if (row_or_col == row_or_col_t::column)
10!
962
            {
963
                ref.column_index(new_index);
10✔
964
            }
965
        }
966
    };
48✔
967

968
    for (auto merged_cell = d_->merged_cells_.begin(); merged_cell != d_->merged_cells_.end(); ++merged_cell)
36✔
969
    {
970
        cell_reference new_top_left = merged_cell->top_left();
24✔
971
        shift_reference(new_top_left);
24✔
972

973
        cell_reference new_bottom_right = merged_cell->bottom_right();
24✔
974
        shift_reference(new_bottom_right);
24✔
975

976
        range_reference new_range{new_top_left, new_bottom_right};
24✔
977
        if (*merged_cell != new_range)
24✔
978
        {
979
            *merged_cell = new_range;
16✔
980
        }
981
    }
982
}
12✔
983

984
bool worksheet::operator==(const worksheet &other) const
2,106✔
985
{
986
    return compare(other, true);
2,106✔
987
}
988

989
bool worksheet::compare(const worksheet &other, bool compare_by_reference) const
2,108✔
990
{
991
    if (compare_by_reference)
2,108✔
992
    {
993
        return d_ == other.d_;
2,106✔
994
    }
995
    else
996
    {
997
        return *d_ == *other.d_;
2✔
998
    }
999
}
1000

1001
bool worksheet::operator!=(const worksheet &other) const
1✔
1002
{
1003
    return !(*this == other);
1✔
1004
}
1005

1006
bool worksheet::operator==(std::nullptr_t) const
×
1007
{
1008
    return d_ == nullptr;
×
1009
}
1010

1011
bool worksheet::operator!=(std::nullptr_t) const
×
1012
{
1013
    return d_ != nullptr;
×
1014
}
1015

1016
void worksheet::operator=(const worksheet &other)
6✔
1017
{
1018
    d_ = other.d_;
6✔
1019
}
6✔
1020

1021
const cell worksheet::operator[](const cell_reference &ref) const
1✔
1022
{
1023
    return cell(ref);
1✔
1024
}
1025

1026
bool worksheet::has_named_range(const std::string &name) const
82✔
1027
{
1028
    return d_->named_ranges_.find(name) != d_->named_ranges_.end();
82✔
1029
}
1030

1031
void worksheet::remove_named_range(const std::string &name)
2✔
1032
{
1033
    auto named_range = d_->named_ranges_.find(name);
2✔
1034

1035
    if (named_range == d_->named_ranges_.end())
2✔
1036
    {
1037
        throw key_not_found(name);
1✔
1038
    }
1039

1040
    d_->named_ranges_.erase(named_range);
1✔
1041
}
1✔
1042

1043
void worksheet::reserve(std::size_t n)
1✔
1044
{
1045
    d_->cell_map_.reserve(n);
1✔
1046
}
1✔
1047

1048
class header_footer worksheet::header_footer() const
25✔
1049
{
1050
    if (!d_->header_footer_.is_set())
25✔
1051
    {
1052
        throw xlnt::invalid_attribute("worksheet \"" + d_->title_ + "\" has no header/footer");
2✔
1053
    }
1054
    return d_->header_footer_.get();
23✔
1055
}
1056

1057
cell_reference worksheet::point_pos(int left, int top) const
1✔
1058
{
1059
    column_t current_column = 1;
1✔
1060
    row_t current_row = 1;
1✔
1061

1062
    double left_pos = 0;
1✔
1063
    double top_pos = 0;
1✔
1064

1065
    while (left_pos <= left)
2✔
1066
    {
1067
        left_pos += column_width(current_column++);
1✔
1068
    }
1069

1070
    while (top_pos <= top)
2✔
1071
    {
1072
        top_pos += row_height(current_row++);
1✔
1073
    }
1074

1075
    return {current_column - 1, current_row - 1};
1✔
1076
}
1077

1078
void worksheet::sheet_state(xlnt::sheet_state state)
×
1079
{
1080
    page_setup().sheet_state(state);
×
1081
}
×
1082

1083
sheet_state worksheet::sheet_state() const
8✔
1084
{
1085
    return page_setup().sheet_state();
8✔
1086
}
1087

1088
void worksheet::add_column_properties(column_t column, const xlnt::column_properties &props)
91,764✔
1089
{
1090
    d_->column_properties_[column] = props;
91,764✔
1091
}
91,764✔
1092

1093
bool worksheet::has_column_properties(column_t column) const
1,485✔
1094
{
1095
    return d_->column_properties_.find(column) != d_->column_properties_.end();
1,485✔
1096
}
1097

1098
column_properties &worksheet::column_properties(column_t column)
1,355✔
1099
{
1100
    return d_->column_properties_[column];
1,355✔
1101
}
1102

1103
const column_properties &worksheet::column_properties(column_t column) const
2✔
1104
{
1105
    auto property = d_->column_properties_.find(column);
2✔
1106

1107
    if (property == d_->column_properties_.end())
2✔
1108
    {
1109
        throw xlnt::key_not_found(std::to_string(column.index));
1✔
1110
    }
1111

1112
    return property->second;
2✔
1113
}
1114

1115
row_properties &worksheet::row_properties(row_t row)
1,442✔
1116
{
1117
    return d_->row_properties_[row];
1,442✔
1118
}
1119

1120
const row_properties &worksheet::row_properties(row_t row) const
16✔
1121
{
1122
    auto property = d_->row_properties_.find(row);
16✔
1123

1124
    if (property == d_->row_properties_.end())
16✔
1125
    {
1126
        throw xlnt::key_not_found(std::to_string(row));
1✔
1127
    }
1128

1129
    return property->second;
30✔
1130
}
1131

1132
void worksheet::add_row_properties(row_t row, const xlnt::row_properties &props)
22✔
1133
{
1134
    d_->row_properties_[row] = props;
22✔
1135
}
22✔
1136

1137
worksheet::iterator worksheet::begin()
3✔
1138
{
1139
    return rows().begin();
3✔
1140
}
1141

1142
worksheet::iterator worksheet::end()
4✔
1143
{
1144
    return rows().end();
4✔
1145
}
1146

1147
worksheet::const_iterator worksheet::cbegin() const
2✔
1148
{
1149
    return rows().cbegin();
2✔
1150
}
1151

1152
worksheet::const_iterator worksheet::cend() const
4✔
1153
{
1154
    return rows().cend();
4✔
1155
}
1156

1157
worksheet::const_iterator worksheet::begin() const
2✔
1158
{
1159
    return cbegin();
2✔
1160
}
1161

1162
worksheet::const_iterator worksheet::end() const
3✔
1163
{
1164
    return cend();
3✔
1165
}
1166

1167
void worksheet::print_title_rows(row_t start, row_t end)
2✔
1168
{
1169
    d_->print_title_rows_ = std::make_pair(start, end);
2✔
1170
}
2✔
1171

1172
optional<std::pair<row_t, row_t>> worksheet::print_title_rows() const
10✔
1173
{
1174
    return d_->print_title_rows_;
10✔
1175
}
1176

1177
void worksheet::print_title_cols(column_t start, column_t end)
2✔
1178
{
1179
    d_->print_title_cols_ = std::make_pair(start, end);
2✔
1180
}
2✔
1181

1182
optional<std::pair<column_t, column_t>> worksheet::print_title_cols() const
10✔
1183
{
1184
    return d_->print_title_cols_;
10✔
1185
}
1186

1187
bool worksheet::has_print_titles() const
57✔
1188
{
1189
    return d_->print_title_cols_.is_set() || d_->print_title_rows_.is_set();
57✔
1190
}
1191

1192
void worksheet::clear_print_titles()
×
1193
{
1194
    d_->print_title_rows_.clear();
×
1195
    d_->print_title_cols_.clear();
×
1196
}
×
1197

1198
void worksheet::print_area(const std::string &print_area)
2✔
1199
{
1200
    d_->print_area_ = range_reference::make_absolute(range_reference(print_area));
2✔
1201
}
2✔
1202

1203
range_reference worksheet::print_area() const
5✔
1204
{
1205
    if (!d_->print_area_.is_set())
5✔
1206
    {
1207
        throw xlnt::invalid_attribute("worksheet \"" + d_->title_ + "\" has no print area");
1✔
1208
    }
1209
    return d_->print_area_.get();
4✔
1210
}
1211

1212
bool worksheet::has_print_area() const
57✔
1213
{
1214
    return d_->print_area_.is_set();
57✔
1215
}
1216

1217
void worksheet::clear_print_area()
×
1218
{
1219
    return d_->print_area_.clear();
×
1220
}
1221

1222
bool worksheet::has_view() const
81✔
1223
{
1224
    return !d_->views_.empty();
81✔
1225
}
1226

1227
const std::vector<sheet_view> & worksheet::views() const
3✔
1228
{
1229
    return d_->views_;
3✔
1230
}
1231

1232
sheet_view &worksheet::view(std::size_t index) const
79✔
1233
{
1234
    if (index >= d_->views_.size())
79✔
1235
    {
1236
        throw xlnt::invalid_parameter("sheet_view index " + std::to_string(index) + " out of range for worksheet \"" + d_->title_ + "\" which only has " + std::to_string(d_->views_.size()) + " views");
2✔
1237
    }
1238

1239
    return d_->views_.at(index);
77✔
1240
}
1241

1242
void worksheet::add_view(const sheet_view &new_view)
342✔
1243
{
1244
    d_->views_.push_back(new_view);
342✔
1245
}
342✔
1246

1247
void worksheet::remove_view(std::size_t index)
2✔
1248
{
1249
    if (index >= d_->views_.size())
2✔
1250
    {
1251
        throw xlnt::invalid_parameter("sheet_view index " + std::to_string(index) + " out of range for worksheet \"" + d_->title_ + "\" which only has " + std::to_string(d_->views_.size()) + " views");
1✔
1252
    }
1253

1254
    d_->views_.erase(d_->views_.begin() + index);
1✔
1255
}
1✔
1256

1257
void worksheet::clear_views()
1✔
1258
{
1259
    d_->views_.clear();
1✔
1260
}
1✔
1261

1262
void worksheet::register_comments_in_manifest()
34✔
1263
{
1264
    workbook().register_worksheet_part(*this, relationship_type::comments);
34✔
1265
}
34✔
1266

1267
void worksheet::register_calc_chain_in_manifest()
20✔
1268
{
1269
    workbook().register_workbook_part(relationship_type::calculation_chain);
20✔
1270
}
20✔
1271

1272
bool worksheet::has_phonetic_properties() const
56✔
1273
{
1274
    return d_->phonetic_properties_.is_set();
56✔
1275
}
1276

1277
phonetic_pr worksheet::phonetic_properties() const
6✔
1278
{
1279
    if (!d_->phonetic_properties_.is_set())
6✔
1280
    {
1281
        return {};
1✔
1282
    }
1283
    return d_->phonetic_properties_.get();
5✔
1284
}
1285

1286
void worksheet::phonetic_properties(const phonetic_pr &phonetic_props)
1✔
1287
{
1288
    d_->phonetic_properties_.set(phonetic_props);
1✔
1289
}
1✔
1290

1291
bool worksheet::has_header_footer() const
59✔
1292
{
1293
    return d_->header_footer_.is_set();
59✔
1294
}
1295

1296
void worksheet::header_footer(const class header_footer &hf)
30✔
1297
{
1298
    d_->header_footer_ = hf;
30✔
1299
}
30✔
1300

1301
void worksheet::clear_page_breaks()
×
1302
{
1303
    d_->row_breaks_.clear();
×
1304
    d_->column_breaks_.clear();
×
1305
}
×
1306

1307
void worksheet::page_break_at_row(row_t row)
×
1308
{
1309
    d_->row_breaks_.push_back(row);
×
1310
}
×
1311

1312
const std::vector<row_t> &worksheet::page_break_rows() const
54✔
1313
{
1314
    return d_->row_breaks_;
54✔
1315
}
1316

1317
void worksheet::page_break_at_column(xlnt::column_t column)
×
1318
{
1319
    d_->column_breaks_.push_back(column);
×
1320
}
×
1321

1322
const std::vector<column_t> &worksheet::page_break_columns() const
54✔
1323
{
1324
    return d_->column_breaks_;
54✔
1325
}
1326

1327
double worksheet::column_width(column_t column) const
35✔
1328
{
1329
    static const auto DefaultColumnWidth = 51.85;
1330

1331
    if (has_column_properties(column))
35!
1332
    {
1333
        return column_properties(column).width.get();
×
1334
    }
1335
    else
1336
    {
1337
        return points_to_pixels(DefaultColumnWidth, 96.0);
35✔
1338
    }
1339
}
1340

1341
double worksheet::row_height(row_t row) const
17✔
1342
{
1343
    static const auto DefaultRowHeight = 15.0;
1344

1345
    if (has_row_properties(row) && row_properties(row).height.is_set())
17!
1346
    {
1347
        return row_properties(row).height.get();
×
1348
    }
1349
    else
1350
    {
1351
        return points_to_pixels(DefaultRowHeight, 96.0);
17✔
1352
    }
1353
}
1354

1355
void worksheet::garbage_collect_formulae()
18✔
1356
{
1357
    workbook().garbage_collect_formulae();
18✔
1358
}
18✔
1359

1360
void worksheet::parent(xlnt::workbook &wb)
2✔
1361
{
1362
    d_->parent_ = wb.d_;
2✔
1363
}
2✔
1364

1365
conditional_format worksheet::conditional_format(const range_reference &ref, const condition &when)
1✔
1366
{
1367
    return workbook().d_->stylesheet_.get().add_conditional_format_rule(d_, ref, when);
1✔
1368
}
1369

1370
path worksheet::path() const
62✔
1371
{
1372
    auto rel = referring_relationship();
62✔
1373
    return xlnt::path(rel.source().path().parent().append(rel.target().path()));
124✔
1374
}
62✔
1375

1376
relationship worksheet::referring_relationship() const
64✔
1377
{
1378
    auto wb = workbook();
64✔
1379
    auto &manifest = wb.manifest();
64✔
1380
    auto wb_rel = manifest.relationship(xlnt::path("/"),
128✔
1381
        relationship_type::office_document);
64✔
1382
    auto ws_rel = manifest.relationship(wb_rel.target().path(),
128✔
1383
        workbook().d_->sheet_title_rel_id_map_.at(title()));
64✔
1384
    return ws_rel;
64✔
1385
}
64✔
1386

1387
sheet_format_properties worksheet::format_properties() const
54✔
1388
{
1389
    return d_->format_properties_;
54✔
1390
}
1391

1392
void worksheet::format_properties(const sheet_format_properties &properties)
3✔
1393
{
1394
    d_->format_properties_ = properties;
3✔
1395
}
3✔
1396

1397
void worksheet::outline_settings(bool visible, bool symbols_below, bool symbols_right, bool apply_styles)
1✔
1398
{
1399
    if (!d_->sheet_properties_.is_set())
1!
1400
    {
1401
        d_->sheet_properties_ = sheet_pr();
1✔
1402
    }
1403

1404
    auto &props = d_->sheet_properties_.get();
1✔
1405
    props.show_outline_symbols.set(visible);
1✔
1406
    props.summary_below.set(symbols_below);
1✔
1407
    props.summary_right.set(symbols_right);
1✔
1408
    props.apply_styles.set(apply_styles);
1✔
1409
}
1✔
1410

1411
bool worksheet::show_outline_symbols() const
2✔
1412
{
1413
    if (d_->sheet_properties_.is_set() && d_->sheet_properties_.get().show_outline_symbols.is_set())
2!
1414
    {
1415
        return d_->sheet_properties_.get().show_outline_symbols.get();
1✔
1416
    }
1417
    return true;
1✔
1418
}
1419

1420
bool worksheet::summary_below() const
2✔
1421
{
1422
    if (d_->sheet_properties_.is_set() && d_->sheet_properties_.get().summary_below.is_set())
2!
1423
    {
1424
        return d_->sheet_properties_.get().summary_below.get();
1✔
1425
    }
1426
    return true;
1✔
1427
}
1428

1429
bool worksheet::summary_right() const
2✔
1430
{
1431
    if (d_->sheet_properties_.is_set() && d_->sheet_properties_.get().summary_right.is_set())
2!
1432
    {
1433
        return d_->sheet_properties_.get().summary_right.get();
1✔
1434
    }
1435
    return true;
1✔
1436
}
1437

1438
bool worksheet::apply_styles() const
2✔
1439
{
1440
    if (d_->sheet_properties_.is_set() && d_->sheet_properties_.get().apply_styles.is_set())
2!
1441
    {
1442
        return d_->sheet_properties_.get().apply_styles.get();
1✔
1443
    }
1444
    return false;
1✔
1445
}
1446

1447
bool worksheet::has_drawing() const
3✔
1448
{
1449
    return d_->drawing_.is_set();
3✔
1450
}
1451

1452
bool worksheet::is_empty() const
×
1453
{
1454
    return d_->cell_map_.empty();
×
1455
}
1456

1457
int worksheet::zoom_scale() const
5✔
1458
{
1459
    if (!has_view())
5✔
1460
    {
1461
        return 100;
1✔
1462
    }
1463

1464
    return view(0).zoom_scale();
4✔
1465
}
1466

1467
void worksheet::zoom_scale(int scale)
2✔
1468
{
1469
    if (!has_view())
2✔
1470
    {
1471
        sheet_view sv;
1✔
1472
        add_view(sv);
1✔
1473
    }
1✔
1474
    view(0).zoom_scale(scale);
2✔
1475
}
2✔
1476

1477
} // namespace xlnt
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc