differential code coverage report with master
Current view: top level - source/worksheet - worksheet.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 88.7 % 608 539 69 539
Current Date: 2025-12-15 23:01:28 Functions: 87.0 % 138 120 18 120
Baseline: coverage_master.info Branches: 88.9 % 539 479 120 958
Baseline Date: 2025-12-15 23:01:27

             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
        

Generated by: LCOV version 2.3.1-beta