differential code coverage report with master
Current view: top level - source/cell - cell.cpp (source / functions) Coverage Total Hit UBC CBC
Current: coverage.info Lines: 91.2 % 501 457 44 457
Current Date: 2026-01-09 22:22:24 Functions: 88.2 % 119 105 14 105
Baseline: coverage_master.info Branches: 83.1 % 543 451 184 902
Baseline Date: 2026-01-09 22:22:23

             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 <cassert>
      28                 :                : #include <cmath>
      29                 :                : 
      30                 :                : #include <xlnt/cell/cell.hpp>
      31                 :                : #include <xlnt/cell/cell_reference.hpp>
      32                 :                : #include <xlnt/cell/comment.hpp>
      33                 :                : #include <xlnt/cell/hyperlink.hpp>
      34                 :                : #include <xlnt/cell/rich_text.hpp>
      35                 :                : #include <xlnt/packaging/manifest.hpp>
      36                 :                : #include <xlnt/packaging/relationship.hpp>
      37                 :                : #include <xlnt/styles/alignment.hpp>
      38                 :                : #include <xlnt/styles/border.hpp>
      39                 :                : #include <xlnt/styles/color.hpp>
      40                 :                : #include <xlnt/styles/fill.hpp>
      41                 :                : #include <xlnt/styles/font.hpp>
      42                 :                : #include <xlnt/styles/format.hpp>
      43                 :                : #include <xlnt/styles/number_format.hpp>
      44                 :                : #include <xlnt/styles/protection.hpp>
      45                 :                : #include <xlnt/styles/style.hpp>
      46                 :                : #include <xlnt/utils/date.hpp>
      47                 :                : #include <xlnt/utils/datetime.hpp>
      48                 :                : #include <xlnt/utils/exceptions.hpp>
      49                 :                : #include <xlnt/utils/time.hpp>
      50                 :                : #include <xlnt/utils/timedelta.hpp>
      51                 :                : #include <xlnt/workbook/workbook.hpp>
      52                 :                : #include <xlnt/worksheet/column_properties.hpp>
      53                 :                : #include <xlnt/worksheet/phonetic_pr.hpp>
      54                 :                : #include <xlnt/worksheet/row_properties.hpp>
      55                 :                : #include <xlnt/worksheet/worksheet.hpp>
      56                 :                : #include <detail/implementations/cell_impl.hpp>
      57                 :                : #include <detail/implementations/format_impl.hpp>
      58                 :                : #include <detail/implementations/hyperlink_impl.hpp>
      59                 :                : #include <detail/implementations/stylesheet.hpp>
      60                 :                : #include <detail/implementations/worksheet_impl.hpp>
      61                 :                : #include <detail/serialization/serialisation_helpers.hpp>
      62                 :                : 
      63                 :                : namespace {
      64                 :                : 
      65                 :CBC          11 : std::pair<bool, double> cast_numeric(const std::string &s)
      66                 :                : {
      67                 :             11 :     size_t len_convert = 0;
      68            [ + ]:             11 :     double result = xlnt::detail::deserialise(s, &len_convert);
      69                 :             11 :     return (len_convert != s.size())
      70         [ +  + ]:             11 :         ? std::make_pair(false, 0.0)
      71                 :             11 :         : std::make_pair(true, result);
      72                 :                : }
      73                 :                : 
      74                 :             14 : std::pair<bool, double> cast_percentage(const std::string &s)
      75                 :                : {
      76         [ +  + ]:             14 :     if (s.back() == '%')
      77                 :                :     {
      78         [ +  + ]:              1 :         auto number = cast_numeric(s.substr(0, s.size() - 1));
      79                 :                : 
      80         [ +  - ]:              1 :         if (number.first)
      81                 :                :         {
      82                 :              1 :             return {true, number.second / 100};
      83                 :                :         }
      84                 :                :     }
      85                 :                : 
      86                 :             13 :     return {false, 0.0};
      87                 :                : }
      88                 :                : 
      89                 :             13 : std::pair<bool, xlnt::time> cast_time(const std::string &s)
      90                 :                : {
      91            [ + ]:             13 :     xlnt::time result;
      92                 :                : 
      93                 :             13 :     std::vector<std::string> time_components;
      94                 :             13 :     std::size_t prev = 0;
      95                 :             13 :     auto colon_index = s.find(':');
      96                 :                : 
      97         [ +  + ]:             18 :     while (colon_index != std::string::npos)
      98                 :                :     {
      99         [ +  + ]:              5 :         time_components.push_back(s.substr(prev, colon_index - prev));
     100                 :              5 :         prev = colon_index + 1;
     101                 :              5 :         colon_index = s.find(':', colon_index + 1);
     102                 :                :     }
     103                 :                : 
     104         [ +  + ]:             13 :     time_components.push_back(s.substr(prev, colon_index - prev));
     105                 :                : 
     106   [ +  +  -  +  :             13 :     if (time_components.size() < 2 || time_components.size() > 3)
                   +  + ]
     107                 :                :     {
     108                 :              9 :         return {false, result};
     109                 :                :     }
     110                 :                : 
     111                 :              4 :     std::vector<double> numeric_components;
     112                 :                : 
     113         [ +  + ]:             12 :     for (const auto & component : time_components)
     114                 :                :     {
     115   [ +  +  +  -  :              9 :         if (component.empty() || (component.substr(0, component.find('.')).size() > 2))
          +  +  +  +  +  
                   -  - ]
     116                 :                :         {
     117                 :              1 :             return {false, result};
     118                 :                :         }
     119                 :                : 
     120         [ +  + ]:             34 :         for (auto d : component)
     121                 :                :         {
     122   [ +  +  -  +  :             26 :             if (!(d >= '0' && d <= '9') && d != '.')
                   -  + ]
     123                 :                :             {
     124                 :UBC           0 :                 return {false, result};
     125                 :                :             }
     126                 :                :         }
     127            [ + ]:CBC           8 :         auto numeric = xlnt::detail::deserialise(component);
     128                 :                : 
     129            [ + ]:              8 :         numeric_components.push_back(numeric);
     130                 :                :     }
     131                 :                : 
     132                 :              3 :     result.hour = static_cast<int>(numeric_components[0]);
     133                 :              3 :     result.minute = static_cast<int>(numeric_components[1]);
     134                 :                : 
     135         [ +  + ]:              3 :     if (std::fabs(static_cast<double>(result.minute) - numeric_components[1]) > std::numeric_limits<double>::epsilon())
     136                 :                :     {
     137                 :              1 :         result.minute = result.hour;
     138                 :              1 :         result.hour = 0;
     139                 :              1 :         result.second = static_cast<int>(numeric_components[1]);
     140                 :              1 :         result.microsecond = static_cast<int>((numeric_components[1] - result.second) * 1E6);
     141                 :                :     }
     142         [ +  + ]:              2 :     else if (numeric_components.size() > 2)
     143                 :                :     {
     144                 :              1 :         result.second = static_cast<int>(numeric_components[2]);
     145                 :              1 :         result.microsecond = static_cast<int>((numeric_components[2] - result.second) * 1E6);
     146                 :                :     }
     147                 :                : 
     148                 :              3 :     return {true, result};
     149                 :             13 : }
     150                 :                : 
     151                 :                : } // namespace
     152                 :                : 
     153                 :                : namespace xlnt {
     154                 :                : 
     155                 :              1 : const std::unordered_map<std::string, int> &cell::error_codes()
     156                 :                : {
     157                 :                :     static const auto codes = std::unordered_map<std::string, int>{
     158                 :UBC           0 :         {"#NULL!", 0},
     159                 :              0 :         {"#DIV/0!", 1},
     160                 :              0 :         {"#VALUE!", 2},
     161                 :              0 :         {"#REF!", 3},
     162                 :              0 :         {"#NAME?", 4},
     163                 :              0 :         {"#NUM!", 5},
     164   [ +  -  +  -  :CBC          10 :         {"#N/A!", 6}};
          +  +  +  -  -  
                   -  - ]
     165                 :                : 
     166                 :              1 :     return codes;
     167   [ +  +  +  +  :              1 : }
          +  +  +  -  -  
                   -  - ]
     168                 :                : 
     169                 :            621 : std::string cell::check_string(const std::string &to_check)
     170                 :                : {
     171                 :                :     // so we can modify it
     172                 :            621 :     std::string s = to_check;
     173                 :                : 
     174         [ +  + ]:            621 :     if (s.size() == 0)
     175                 :                :     {
     176                 :              2 :         return s;
     177                 :                :     }
     178         [ +  + ]:            619 :     else if (s.size() > 32767)
     179                 :                :     {
     180            [ + ]:              1 :         s = s.substr(0, 32767); // max string length in Excel
     181                 :                :     }
     182                 :                : 
     183         [ +  + ]:          68427 :     for (char c : s)
     184                 :                :     {
     185   [ +  -  +  +  :          67837 :         if (c >= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)))
          +  +  +  +  +  
                +  +  + ]
     186                 :                :         {
     187            [ + ]:             29 :             throw illegal_character(c);
     188                 :                :         }
     189                 :                :     }
     190                 :                : 
     191                 :            590 :     return s;
     192                 :             29 : }
     193                 :                : 
     194                 :           3284 : cell::cell(detail::cell_impl *d)
     195                 :           3284 :     : d_(d)
     196                 :                : {
     197                 :           3284 : }
     198                 :                : 
     199                 :            957 : bool cell::garbage_collectible() const
     200                 :                : {
     201                 :            957 :     return d_->is_garbage_collectible();
     202                 :                : }
     203                 :                : 
     204                 :              1 : void cell::value(std::nullptr_t)
     205                 :                : {
     206                 :              1 :     clear_value();
     207                 :              1 : }
     208                 :                : 
     209                 :             10 : void cell::value(bool boolean_value)
     210                 :                : {
     211                 :             10 :     d_->type_ = type::boolean;
     212         [ +  + ]:             10 :     d_->value_numeric_ = boolean_value ? 1.0 : 0.0;
     213                 :             10 : }
     214                 :                : 
     215                 :             14 : void cell::value(int int_value)
     216                 :                : {
     217                 :             14 :     d_->value_numeric_ = static_cast<double>(int_value);
     218                 :             14 :     d_->type_ = type::number;
     219                 :             14 : }
     220                 :                : 
     221                 :              2 : void cell::value(unsigned int int_value)
     222                 :                : {
     223                 :              2 :     d_->value_numeric_ = static_cast<double>(int_value);
     224                 :              2 :     d_->type_ = type::number;
     225                 :              2 : }
     226                 :                : 
     227                 :              2 : void cell::value(long long int int_value)
     228                 :                : {
     229                 :              2 :     d_->value_numeric_ = static_cast<double>(int_value);
     230                 :              2 :     d_->type_ = type::number;
     231                 :              2 : }
     232                 :                : 
     233                 :              2 : void cell::value(unsigned long long int int_value)
     234                 :                : {
     235                 :              2 :     d_->value_numeric_ = static_cast<double>(int_value);
     236                 :              2 :     d_->type_ = type::number;
     237                 :              2 : }
     238                 :                : 
     239                 :              2 : void cell::value(float float_value)
     240                 :                : {
     241                 :              2 :     d_->value_numeric_ = static_cast<double>(float_value);
     242                 :              2 :     d_->type_ = type::number;
     243                 :              2 : }
     244                 :                : 
     245                 :              6 : void cell::value(double float_value)
     246                 :                : {
     247                 :              6 :     d_->value_numeric_ = static_cast<double>(float_value);
     248                 :              6 :     d_->type_ = type::number;
     249                 :              6 : }
     250                 :                : 
     251                 :            325 : void cell::value(const std::string &s)
     252                 :                : {
     253      [ +  +  + ]:            325 :     value(rich_text(check_string(s)));
     254                 :            296 : }
     255                 :                : 
     256                 :            296 : void cell::value(const rich_text &text)
     257                 :                : {
     258         [ +  + ]:            296 :     check_string(text.plain_text());
     259                 :                : 
     260                 :            296 :     value_no_check(text);
     261                 :            296 : }
     262                 :                : 
     263                 :            124 : void cell::value(const char *c)
     264                 :                : {
     265         [ +  + ]:            124 :     value(std::string(c));
     266                 :            124 : }
     267                 :                : 
     268                 :              7 : void cell::value(const cell c)
     269                 :                : {
     270   [ +  +  +  +  :              7 :     if (c.worksheet().workbook() != worksheet().workbook())
                +  +  + ]
     271                 :                :     {
     272                 :              5 :         copy_from_other_workbook(c);
     273                 :              5 :         return;
     274                 :                :     }
     275                 :                : 
     276                 :                :     // Same workbook: shallow copy (existing behavior)
     277                 :              2 :     d_->type_ = c.d_->type_;
     278                 :              2 :     d_->value_numeric_ = c.d_->value_numeric_;
     279                 :              2 :     d_->value_text_ = c.d_->value_text_;
     280                 :              2 :     d_->hyperlink_ = c.d_->hyperlink_;
     281                 :              2 :     d_->formula_ = c.d_->formula_;
     282                 :              2 :     d_->format_ = c.d_->format_;
     283                 :                : }
     284                 :                : 
     285                 :            299 : void cell::value_no_check(const rich_text &text)
     286                 :                : {
     287                 :            299 :     d_->type_ = type::shared_string;
     288         [ +  + ]:            299 :     d_->value_numeric_ = static_cast<double>(workbook().add_shared_string(text));
     289                 :            299 : }
     290                 :                : 
     291                 :              5 : void cell::copy_from_other_workbook(const cell &source)
     292                 :                : {
     293                 :              5 :     d_->type_ = source.d_->type_;
     294                 :                : 
     295                 :                :     // Handle shared_string: remap to destination workbook
     296         [ +  + ]:              5 :     if (source.data_type() == type::shared_string)
     297                 :                :     {
     298         [ +  + ]:              3 :         value_no_check(source.value<rich_text>());
     299                 :                :     }
     300                 :                :     else
     301                 :                :     {
     302                 :              2 :         d_->value_numeric_ = source.d_->value_numeric_;
     303                 :                :     }
     304                 :                : 
     305                 :              5 :     d_->value_text_ = source.d_->value_text_;
     306                 :              5 :     d_->formula_ = source.d_->formula_;
     307                 :                : 
     308                 :                :     // Copy external hyperlinks; internal hyperlinks (cell/range references)
     309                 :                :     // are not yet implemented as they would need worksheet title remapping.
     310                 :                :     // TODO: implement internal hyperlink remapping.
     311         [ +  + ]:              5 :     if (source.has_hyperlink())
     312                 :                :     {
     313            [ + ]:              1 :         auto copy_hyperlink = source.hyperlink();
     314                 :                : 
     315      [ +  +  - ]:              1 :         if (copy_hyperlink.external())
     316                 :                :         {
     317      [ +  +  + ]:              1 :             hyperlink(copy_hyperlink.url(), copy_hyperlink.display());
     318                 :                :         }
     319                 :                :     }
     320                 :                : 
     321         [ +  + ]:              5 :     if (source.has_format())
     322                 :                :     {
     323         [ +  + ]:              1 :         format(source.format());
     324                 :                :     }
     325                 :                :     else
     326                 :                :     {
     327                 :              4 :         d_->format_.clear();
     328                 :                :     }
     329                 :              5 : }
     330                 :                : 
     331                 :              3 : void cell::value(const date &d)
     332                 :                : {
     333                 :              3 :     d_->type_ = type::number;
     334                 :              3 :     d_->value_numeric_ = d.to_number(base_date());
     335         [ +  + ]:              3 :     number_format(number_format::date_yyyymmdd2());
     336                 :              3 : }
     337                 :                : 
     338                 :              5 : void cell::value(const datetime &d)
     339                 :                : {
     340                 :              5 :     d_->type_ = type::number;
     341                 :              5 :     d_->value_numeric_ = d.to_number(base_date());
     342         [ +  + ]:              5 :     number_format(number_format::date_datetime());
     343                 :              5 : }
     344                 :                : 
     345                 :              2 : void cell::value(const time &t)
     346                 :                : {
     347                 :              2 :     d_->type_ = type::number;
     348                 :              2 :     d_->value_numeric_ = t.to_number();
     349         [ +  + ]:              2 :     number_format(number_format::date_time6());
     350                 :              2 : }
     351                 :                : 
     352                 :              2 : void cell::value(const timedelta &t)
     353                 :                : {
     354                 :              2 :     d_->type_ = type::number;
     355                 :              2 :     d_->value_numeric_ = t.to_number();
     356      [ +  +  + ]:              2 :     number_format(xlnt::number_format("[hh]:mm:ss"));
     357                 :              2 : }
     358                 :                : 
     359                 :              7 : row_t cell::row() const
     360                 :                : {
     361                 :              7 :     return d_->row_;
     362                 :                : }
     363                 :                : 
     364                 :             39 : column_t cell::column() const
     365                 :                : {
     366                 :             39 :     return d_->column_;
     367                 :                : }
     368                 :                : 
     369                 :              1 : column_t::index_t cell::column_index() const
     370                 :                : {
     371                 :              1 :     return d_->column_.index;
     372                 :                : }
     373                 :                : 
     374                 :            774 : void cell::merged(bool merged)
     375                 :                : {
     376                 :            774 :     d_->is_merged_ = merged;
     377                 :            774 : }
     378                 :                : 
     379                 :UBC           0 : bool cell::is_merged() const
     380                 :                : {
     381                 :              0 :     return d_->is_merged_;
     382                 :                : }
     383                 :                : 
     384                 :CBC         964 : bool cell::phonetics_visible() const
     385                 :                : {
     386                 :            964 :     return d_->phonetics_visible_;
     387                 :                : }
     388                 :                : 
     389                 :              2 : void cell::show_phonetics(bool phonetics)
     390                 :                : {
     391                 :              2 :     d_->phonetics_visible_ = phonetics;
     392                 :              2 : }
     393                 :                : 
     394                 :              7 : bool cell::is_date() const
     395                 :                : {
     396                 :              7 :     return data_type() == type::number
     397         [ +  - ]:              4 :         && has_format()
     398   [ +  +  +  +  :             11 :         && number_format().is_date_format();
          +  +  +  +  -  
                      - ]
     399                 :                : }
     400                 :                : 
     401                 :           1124 : cell_reference cell::reference() const
     402                 :                : {
     403            [ + ]:           1124 :     return {d_->column_, d_->row_};
     404                 :                : }
     405                 :                : 
     406                 :             17 : bool cell::compare(const cell &other, bool compare_by_reference) const
     407                 :                : {
     408         [ +  - ]:             17 :     if (compare_by_reference)
     409                 :                :     {
     410                 :             17 :         return d_ == other.d_;
     411                 :                :     }
     412                 :                :     else
     413                 :                :     {
     414                 :UBC           0 :         return *d_ == *other.d_;
     415                 :                :     }
     416                 :                : }
     417                 :                : 
     418                 :CBC          17 : bool cell::operator==(const cell &comparand) const
     419                 :                : {
     420                 :             17 :     return compare(comparand, true);
     421                 :                : }
     422                 :                : 
     423                 :              2 : bool cell::operator!=(const cell &comparand) const
     424                 :                : {
     425                 :              2 :     return !(*this == comparand);
     426                 :                : }
     427                 :                : 
     428                 :              1 : cell &cell::operator=(const cell &rhs) = default;
     429                 :                : 
     430                 :             65 : hyperlink cell::hyperlink() const
     431                 :                : {
     432         [ +  + ]:             65 :     return xlnt::hyperlink(&d_->hyperlink_.get());
     433                 :                : }
     434                 :                : 
     435                 :             41 : void cell::hyperlink(const std::string &url, const std::string &display)
     436                 :                : {
     437         [ +  + ]:             41 :     if (url.empty())
     438                 :                :     {
     439            [ + ]:              1 :         throw invalid_parameter();
     440                 :                :     }
     441                 :                : 
     442            [ + ]:             40 :     auto ws = worksheet();
     443         [ +  + ]:             40 :     auto &manifest = ws.workbook().manifest();
     444                 :                : 
     445            [ + ]:             40 :     d_->hyperlink_ = detail::hyperlink_impl();
     446                 :                : 
     447                 :                :     // check for existing relationships
     448         [ +  + ]:             40 :     auto relationships = manifest.relationships(ws.path(), relationship_type::hyperlink);
     449            [ + ]:             40 :     auto relation = std::find_if(relationships.cbegin(), relationships.cend(),
     450                 :             57 :         [&url](xlnt::relationship rel) { return rel.target().path().string() == url; });
     451         [ +  + ]:             40 :     if (relation != relationships.end())
     452                 :                :     {
     453         [ +  + ]:             30 :         d_->hyperlink_.get().relationship = *relation;
     454                 :                :     }
     455                 :                :     else
     456                 :                :     { // register a new relationship
     457                 :                :         auto rel_id = manifest.register_relationship(
     458      [ +  +  + ]:             20 :             uri(ws.path().string()),
     459                 :                :             relationship_type::hyperlink,
     460            [ + ]:             20 :             uri(url),
     461            [ + ]:             10 :             target_mode::external);
     462                 :                :         // TODO: make manifest::register_relationship return the created relationship instead of rel id
     463      [ +  +  + ]:             10 :         d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id);
     464                 :             10 :     }
     465                 :                :     // if a value is already present, the display string is ignored
     466         [ +  + ]:             40 :     if (has_value())
     467                 :                :     {
     468         [ +  + ]:             34 :         d_->hyperlink_.get().display.set(to_string());
     469                 :                :     }
     470                 :                :     else
     471                 :                :     {
     472   [ +  +  +  + ]:              6 :         d_->hyperlink_.get().display.set(display.empty() ? url : display);
     473      [ +  +  + ]:              6 :         value(hyperlink().display());
     474                 :                :     }
     475                 :             40 : }
     476                 :                : 
     477                 :              4 : void cell::hyperlink(xlnt::cell target, const std::string &display)
     478                 :                : {
     479                 :                :     // TODO: should this computed value be a method on a cell?
     480   [ +  +  +  +  :              4 :     const auto cell_address = target.worksheet().title() + "!" + target.reference().to_string();
                   +  + ]
     481                 :                : 
     482            [ + ]:              4 :     d_->hyperlink_ = detail::hyperlink_impl();
     483            [ + ]:              8 :     d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
     484   [ +  +  +  +  :             28 :         uri(""), uri(cell_address), target_mode::internal);
                      + ]
     485                 :                :     // if a value is already present, the display string is ignored
     486         [ +  + ]:              4 :     if (has_value())
     487                 :                :     {
     488         [ +  + ]:              1 :         d_->hyperlink_.get().display.set(to_string());
     489                 :                :     }
     490                 :                :     else
     491                 :                :     {
     492   [ +  +  +  + ]:              3 :         d_->hyperlink_.get().display.set(display.empty() ? cell_address : display);
     493      [ +  +  + ]:              3 :         value(hyperlink().display());
     494                 :                :     }
     495                 :              4 : }
     496                 :                : 
     497                 :              3 : void cell::hyperlink(xlnt::range target, const std::string &display)
     498                 :                : {
     499                 :                :     // TODO: should this computed value be a method on a cell?
     500   [ +  +  +  +  :              3 :     const auto range_address = target.target_worksheet().title() + "!" + target.reference().to_string();
                   +  + ]
     501                 :                : 
     502            [ + ]:              3 :     d_->hyperlink_ = detail::hyperlink_impl();
     503            [ + ]:              6 :     d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
     504   [ +  +  +  +  :             21 :         uri(""), uri(range_address), target_mode::internal);
                      + ]
     505                 :                : 
     506                 :                :     // if a value is already present, the display string is ignored
     507         [ +  + ]:              3 :     if (has_value())
     508                 :                :     {
     509         [ +  + ]:              1 :         d_->hyperlink_.get().display.set(to_string());
     510                 :                :     }
     511                 :                :     else
     512                 :                :     {
     513   [ +  +  +  + ]:              2 :         d_->hyperlink_.get().display.set(display.empty() ? range_address : display);
     514      [ +  +  + ]:              2 :         value(hyperlink().display());
     515                 :                :     }
     516                 :              3 : }
     517                 :                : 
     518                 :             21 : void cell::formula(const std::string &formula)
     519                 :                : {
     520         [ +  + ]:             21 :     if (formula.empty())
     521                 :                :     {
     522                 :              1 :         return clear_formula();
     523                 :                :     }
     524                 :                : 
     525         [ +  + ]:             20 :     if (formula[0] == '=')
     526                 :                :     {
     527            [ + ]:              8 :         d_->formula_ = formula.substr(1);
     528                 :                :     }
     529                 :                :     else
     530                 :                :     {
     531                 :             12 :         d_->formula_ = formula;
     532                 :                :     }
     533                 :                : 
     534         [ +  + ]:             20 :     worksheet().register_calc_chain_in_manifest();
     535                 :                : }
     536                 :                : 
     537                 :           2208 : bool cell::has_formula() const
     538                 :                : {
     539                 :           2208 :     return d_->formula_.is_set();
     540                 :                : }
     541                 :                : 
     542                 :             19 : std::string cell::formula() const
     543                 :                : {
     544                 :             19 :     return d_->formula_.get();
     545                 :                : }
     546                 :                : 
     547                 :            794 : void cell::clear_formula()
     548                 :                : {
     549         [ +  + ]:            794 :     if (has_formula())
     550                 :                :     {
     551                 :             18 :         d_->formula_.clear();
     552         [ +  + ]:             18 :         worksheet().garbage_collect_formulae();
     553                 :                :     }
     554                 :            794 : }
     555                 :                : 
     556                 :             21 : std::string cell::error() const
     557                 :                : {
     558         [ +  + ]:             21 :     if (d_->type_ != type::error)
     559                 :                :     {
     560         [ +  + ]:             21 :         throw xlnt::exception("called error() when cell type is not error");
     561                 :                :     }
     562                 :             14 :     return value<std::string>();
     563                 :                : }
     564                 :                : 
     565                 :             17 : void cell::error(const std::string &error)
     566                 :                : {
     567   [ +  +  +  +  :             17 :     if (error.length() == 0 || error[0] != '#')
                   +  + ]
     568                 :                :     {
     569            [ + ]:              2 :         throw invalid_data_type();
     570                 :                :     }
     571                 :                : 
     572                 :             15 :     d_->value_text_.plain_text(error, false);
     573                 :             15 :     d_->type_ = type::error;
     574                 :             15 : }
     575                 :                : 
     576                 :              1 : cell cell::offset(int column, int row)
     577                 :                : {
     578   [ +  +  +  + ]:              1 :     return worksheet().cell(reference().make_offset(column, row));
     579                 :                : }
     580                 :                : 
     581                 :            591 : worksheet cell::worksheet()
     582                 :                : {
     583                 :            591 :     return xlnt::worksheet(d_->parent_);
     584                 :                : }
     585                 :                : 
     586                 :            266 : const worksheet cell::worksheet() const
     587                 :                : {
     588                 :            266 :     return xlnt::worksheet(d_->parent_);
     589                 :                : }
     590                 :                : 
     591                 :            467 : workbook cell::workbook()
     592                 :                : {
     593         [ +  + ]:            467 :     return worksheet().workbook();
     594                 :                : }
     595                 :                : 
     596                 :            209 : const workbook cell::workbook() const
     597                 :                : {
     598         [ +  + ]:            209 :     return worksheet().workbook();
     599                 :                : }
     600                 :                : 
     601                 :             35 : std::pair<int, int> cell::anchor() const
     602                 :                : {
     603                 :             35 :     double left = 0;
     604                 :                : 
     605   [ +  +  +  +  :             35 :     for (column_t column_index = 1; column_index <= d_->column_ - 1; column_index++)
                   -  + ]
     606                 :                :     {
     607      [ #  #  # ]:UBC           0 :         left += worksheet().column_width(column_index);
     608                 :                :     }
     609                 :                : 
     610                 :CBC          35 :     double top = 0;
     611                 :                : 
     612         [ +  + ]:             51 :     for (row_t row_index = 1; row_index <= d_->row_ - 1; row_index++)
     613                 :                :     {
     614         [ +  + ]:             16 :         top += worksheet().row_height(row_index);
     615                 :                :     }
     616                 :                : 
     617                 :             35 :     return {static_cast<int>(left), static_cast<int>(top)};
     618                 :                : }
     619                 :                : 
     620                 :           2983 : cell::type cell::data_type() const
     621                 :                : {
     622                 :           2983 :     return d_->type_;
     623                 :                : }
     624                 :                : 
     625                 :            151 : void cell::data_type(type t)
     626                 :                : {
     627                 :            151 :     d_->type_ = t;
     628                 :            151 : }
     629                 :                : 
     630                 :             50 : number_format cell::computed_number_format() const
     631                 :                : {
     632                 :             50 :     return xlnt::number_format();
     633                 :                : }
     634                 :                : 
     635                 :UBC           0 : font cell::computed_font() const
     636                 :                : {
     637                 :              0 :     return xlnt::font();
     638                 :                : }
     639                 :                : 
     640                 :              0 : fill cell::computed_fill() const
     641                 :                : {
     642                 :              0 :     return xlnt::fill();
     643                 :                : }
     644                 :                : 
     645                 :              0 : border cell::computed_border() const
     646                 :                : {
     647                 :              0 :     return xlnt::border();
     648                 :                : }
     649                 :                : 
     650                 :              0 : alignment cell::computed_alignment() const
     651                 :                : {
     652                 :              0 :     return xlnt::alignment();
     653                 :                : }
     654                 :                : 
     655                 :              0 : protection cell::computed_protection() const
     656                 :                : {
     657            [ # ]:              0 :     return xlnt::protection();
     658                 :                : }
     659                 :                : 
     660                 :CBC         767 : void cell::clear_value()
     661                 :                : {
     662                 :            767 :     d_->value_numeric_ = 0;
     663                 :            767 :     d_->value_text_.clear();
     664                 :            767 :     d_->type_ = cell::type::empty;
     665                 :            767 :     clear_formula();
     666                 :            767 : }
     667                 :                : 
     668                 :                : template <>
     669                 :              7 : bool cell::value() const
     670                 :                : {
     671                 :              7 :     return d_->value_numeric_ != 0.0;
     672                 :                : }
     673                 :                : 
     674                 :                : template <>
     675                 :             24 : int cell::value() const
     676                 :                : {
     677                 :             24 :     return static_cast<int>(d_->value_numeric_);
     678                 :                : }
     679                 :                : 
     680                 :                : template <>
     681                 :              1 : long long int cell::value() const
     682                 :                : {
     683                 :              1 :     return static_cast<long long int>(d_->value_numeric_);
     684                 :                : }
     685                 :                : 
     686                 :                : template <>
     687                 :              1 : unsigned int cell::value() const
     688                 :                : {
     689                 :              1 :     return static_cast<unsigned int>(d_->value_numeric_);
     690                 :                : }
     691                 :                : 
     692                 :                : template <>
     693                 :              1 : unsigned long long cell::value() const
     694                 :                : {
     695                 :              1 :     return static_cast<unsigned long long>(d_->value_numeric_);
     696                 :                : }
     697                 :                : 
     698                 :                : template <>
     699                 :              1 : float cell::value() const
     700                 :                : {
     701                 :              1 :     return static_cast<float>(d_->value_numeric_);
     702                 :                : }
     703                 :                : 
     704                 :                : template <>
     705                 :             67 : double cell::value() const
     706                 :                : {
     707                 :             67 :     return static_cast<double>(d_->value_numeric_);
     708                 :                : }
     709                 :                : 
     710                 :                : template <>
     711                 :              3 : time cell::value() const
     712                 :                : {
     713                 :              3 :     return time::from_number(d_->value_numeric_);
     714                 :                : }
     715                 :                : 
     716                 :                : template <>
     717                 :UBC           0 : datetime cell::value() const
     718                 :                : {
     719                 :              0 :     return datetime::from_number(d_->value_numeric_, base_date());
     720                 :                : }
     721                 :                : 
     722                 :                : template <>
     723                 :              0 : date cell::value() const
     724                 :                : {
     725                 :              0 :     return date::from_number(static_cast<int>(d_->value_numeric_), base_date());
     726                 :                : }
     727                 :                : 
     728                 :                : template <>
     729                 :              0 : timedelta cell::value() const
     730                 :                : {
     731                 :              0 :     return timedelta::from_number(d_->value_numeric_);
     732                 :                : }
     733                 :                : 
     734                 :CBC           1 : void cell::alignment(const class alignment &alignment_)
     735                 :                : {
     736   [ -  +  -  +  :              1 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  -  -  
                      - ]
     737      [ +  +  + ]:              1 :     format(new_format.alignment(alignment_, optional<bool>(true)));
     738                 :              1 : }
     739                 :                : 
     740                 :              1 : void cell::border(const class border &border_)
     741                 :                : {
     742   [ -  +  -  +  :              1 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  -  -  
                      - ]
     743      [ +  +  + ]:              1 :     format(new_format.border(border_, optional<bool>(true)));
     744                 :              1 : }
     745                 :                : 
     746                 :             13 : void cell::fill(const class fill &fill_)
     747                 :                : {
     748   [ +  +  +  +  :             13 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  +  -  
                      - ]
     749      [ +  +  + ]:             13 :     format(new_format.fill(fill_, optional<bool>(true)));
     750                 :             13 : }
     751                 :                : 
     752                 :             26 : void cell::font(const class font &font_)
     753                 :                : {
     754   [ +  +  +  +  :             26 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  +  -  
                      - ]
     755      [ +  +  + ]:             26 :     format(new_format.font(font_, optional<bool>(true)));
     756                 :             26 : }
     757                 :                : 
     758                 :             21 : void cell::number_format(const class number_format &number_format_)
     759                 :                : {
     760   [ +  +  +  +  :             21 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  +  -  
                      - ]
     761      [ +  +  + ]:             21 :     format(new_format.number_format(number_format_, optional<bool>(true)));
     762                 :             21 : }
     763                 :                : 
     764                 :              1 : void cell::protection(const class protection &protection_)
     765                 :                : {
     766   [ -  +  -  +  :              1 :     auto new_format = has_format() ? modifiable_format() : workbook().create_format();
             +  +  -  -  
                      - ]
     767      [ +  +  + ]:              1 :     format(new_format.protection(protection_, optional<bool>(true)));
     768                 :              1 : }
     769                 :                : 
     770                 :                : template <>
     771                 :            219 : std::string cell::value() const
     772                 :                : {
     773         [ +  + ]:            219 :     return value<rich_text>().plain_text();
     774                 :                : }
     775                 :                : 
     776                 :                : template <>
     777                 :            225 : rich_text cell::value() const
     778                 :                : {
     779         [ +  + ]:            225 :     if (data_type() == cell::type::shared_string)
     780                 :                :     {
     781      [ +  +  + ]:            196 :         return workbook().shared_strings(static_cast<std::size_t>(d_->value_numeric_));
     782                 :                :     }
     783                 :                : 
     784                 :             29 :     return d_->value_text_;
     785                 :                : }
     786                 :                : 
     787                 :            115 : bool cell::has_value() const
     788                 :                : {
     789                 :            115 :     return d_->type_ != cell::type::empty;
     790                 :                : }
     791                 :                : 
     792                 :             50 : std::string cell::to_string() const
     793                 :                : {
     794            [ + ]:             50 :     auto nf = computed_number_format();
     795                 :                : 
     796   [ +  +  +  +  :             50 :     switch (data_type())
                      - ]
     797                 :                :     {
     798                 :              2 :     case cell::type::empty:
     799            [ + ]:              4 :         return "";
     800                 :              5 :     case cell::type::date:
     801                 :                :     case cell::type::number:
     802         [ +  + ]:              5 :         return nf.format(value<double>(), base_date());
     803                 :             39 :     case cell::type::inline_string:
     804                 :                :     case cell::type::shared_string:
     805                 :                :     case cell::type::formula_string:
     806                 :                :     case cell::type::error:
     807         [ +  + ]:             39 :         return nf.format(value<std::string>());
     808                 :              4 :     case cell::type::boolean:
     809      [ +  +  + ]:              8 :         return value<double>() == 0.0 ? "FALSE" : "TRUE";
     810                 :                :     }
     811                 :                : 
     812            [ # ]:UBC           0 :     return "";
     813                 :CBC          50 : }
     814                 :                : 
     815                 :           1062 : bool cell::has_format() const
     816                 :                : {
     817                 :           1062 :     return d_->format_.is_set();
     818                 :                : }
     819                 :                : 
     820                 :            108 : void cell::format(const class format new_format)
     821                 :                : {
     822                 :                :     // Check if format belongs to a different workbook (dangling pointer risk)
     823   [ +  +  +  + ]:            108 :     if (!workbook().owns_format(new_format))
     824                 :                :     {
     825                 :              2 :         copy_format_from_other_workbook(new_format);
     826                 :              2 :         return;
     827                 :                :     }
     828                 :                : 
     829                 :                :     // Same workbook: direct assignment (original behavior)
     830                 :            106 :     d_->format_ = new_format.d_;
     831                 :                : }
     832                 :                : 
     833                 :              2 : void cell::copy_format_from_other_workbook(const class format &source_format)
     834                 :                : {
     835         [ +  + ]:              2 :     auto cloned_format = workbook().clone_format_from(source_format);
     836                 :                : 
     837                 :                :     // Use the cloned format
     838            [ + ]:              2 :     d_->format_ = cloned_format.d_;
     839                 :              2 : }
     840                 :                : 
     841                 :             13 : calendar cell::base_date() const
     842                 :                : {
     843         [ +  + ]:             13 :     return workbook().base_date();
     844                 :                : }
     845                 :                : 
     846                 :              4 : bool operator==(std::nullptr_t, const cell &cell)
     847                 :                : {
     848                 :              4 :     return cell.data_type() == cell::type::empty;
     849                 :                : }
     850                 :                : 
     851                 :              2 : bool operator==(const cell &cell, std::nullptr_t)
     852                 :                : {
     853                 :              2 :     return nullptr == cell;
     854                 :                : }
     855                 :                : 
     856                 :UBC           0 : bool operator!=(std::nullptr_t, const cell &cell)
     857                 :                : {
     858                 :              0 :     return !(nullptr == cell);
     859                 :                : }
     860                 :                : 
     861                 :              0 : bool operator!=(const cell &cell, std::nullptr_t)
     862                 :                : {
     863                 :              0 :     return nullptr != cell;
     864                 :                : }
     865                 :                : 
     866                 :CBC           6 : std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
     867                 :                : {
     868         [ +  + ]:              6 :     return stream << cell.to_string();
     869                 :                : }
     870                 :                : 
     871                 :             23 : void cell::value(const std::string &value_string, bool infer_type)
     872                 :                : {
     873            [ + ]:             23 :     value(value_string);
     874                 :                : 
     875   [ +  -  -  +  :             23 :     if (!infer_type || value_string.empty())
                   -  + ]
     876                 :                :     {
     877                 :              9 :         return;
     878                 :                :     }
     879                 :                : 
     880   [ +  +  +  +  :             23 :     if (value_string.front() == '=' && value_string.size() > 1)
                   +  + ]
     881                 :                :     {
     882            [ + ]:              2 :         formula(value_string);
     883                 :              2 :         return;
     884                 :                :     }
     885                 :                : 
     886   [ +  +  +  -  :             21 :     if (value_string.front() == '#' && value_string.size() > 1)
                   +  + ]
     887                 :                :     {
     888            [ + ]:              7 :         error(value_string);
     889                 :              7 :         return;
     890                 :                :     }
     891                 :                : 
     892            [ + ]:             14 :     auto percentage = cast_percentage(value_string);
     893                 :                : 
     894         [ +  + ]:             14 :     if (percentage.first)
     895                 :                :     {
     896                 :              1 :         d_->value_numeric_ = percentage.second;
     897                 :              1 :         d_->type_ = cell::type::number;
     898         [ +  + ]:              1 :         number_format(xlnt::number_format::percentage());
     899                 :                :     }
     900                 :                :     else
     901                 :                :     {
     902            [ + ]:             13 :         auto time = cast_time(value_string);
     903                 :                : 
     904         [ +  + ]:             13 :         if (time.first)
     905                 :                :         {
     906                 :              3 :             d_->type_ = cell::type::number;
     907         [ +  + ]:              3 :             number_format(number_format::date_time6());
     908            [ + ]:              3 :             d_->value_numeric_ = time.second.to_number();
     909                 :                :         }
     910                 :                :         else
     911                 :                :         {
     912            [ + ]:             10 :             auto numeric = cast_numeric(value_string);
     913                 :                : 
     914         [ +  + ]:             10 :             if (numeric.first)
     915                 :                :             {
     916                 :              8 :                 d_->value_numeric_ = numeric.second;
     917                 :              8 :                 d_->type_ = cell::type::number;
     918                 :                :             }
     919                 :                :         }
     920                 :                :     }
     921                 :                : }
     922                 :                : 
     923                 :              2 : void cell::clear_format()
     924                 :                : {
     925         [ +  - ]:              2 :     if (d_->format_.is_set())
     926                 :              2 :         d_->format_.clear();
     927                 :              2 : }
     928                 :                : 
     929                 :              2 : void cell::clear_style()
     930                 :                : {
     931         [ +  - ]:              2 :     if (has_format())
     932                 :                :     {
     933         [ +  + ]:              2 :         modifiable_format().clear_style();
     934                 :                :     }
     935                 :              2 : }
     936                 :                : 
     937                 :              4 : void cell::style(const class style &new_style)
     938                 :                : {
     939   [ +  +  +  +  :              4 :     auto new_format = has_format() ? format() : workbook().create_format();
             +  +  +  -  
                      - ]
     940                 :                : 
     941         [ +  + ]:              4 :     new_format.border(new_style.border());
     942         [ +  + ]:              4 :     new_format.fill(new_style.fill());
     943         [ +  + ]:              4 :     new_format.font(new_style.font());
     944         [ +  + ]:              4 :     new_format.number_format(new_style.number_format());
     945                 :                : 
     946      [ +  +  + ]:              4 :     format(new_format.style(new_style));
     947                 :              4 : }
     948                 :                : 
     949                 :              2 : void cell::style(const std::string &style_name)
     950                 :                : {
     951      [ +  +  + ]:              3 :     style(workbook().style(style_name));
     952                 :              1 : }
     953                 :                : 
     954                 :              7 : style cell::style()
     955                 :                : {
     956   [ +  -  +  +  :              7 :     if (!has_format() || !format().has_style())
          +  +  +  -  +  
                +  -  - ]
     957                 :                :     {
     958            [ + ]:              1 :         throw invalid_attribute();
     959                 :                :     }
     960                 :                : 
     961            [ + ]:              6 :     auto f = format();
     962                 :                : 
     963            [ + ]:             12 :     return f.style();
     964                 :              6 : }
     965                 :                : 
     966                 :UBC           0 : const style cell::style() const
     967                 :                : {
     968   [ #  #  #  #  :              0 :     if (!has_format() || !format().has_style())
          #  #  #  #  #  
                #  #  # ]
     969                 :                :     {
     970            [ # ]:              0 :         throw invalid_attribute();
     971                 :                :     }
     972                 :                : 
     973         [ #  # ]:              0 :     return format().style();
     974                 :                : }
     975                 :                : 
     976                 :CBC           6 : bool cell::has_style() const
     977                 :                : {
     978   [ +  +  +  +  :              6 :     return has_format() && format().has_style();
          +  +  +  +  -  
                      - ]
     979                 :                : }
     980                 :                : 
     981                 :             11 : format cell::modifiable_format()
     982                 :                : {
     983         [ -  + ]:             11 :     if (!d_->format_.is_set())
     984                 :                :     {
     985            [ # ]:UBC           0 :         throw invalid_attribute();
     986                 :                :     }
     987                 :                : 
     988         [ +  + ]:CBC          11 :     return xlnt::format(d_->format_);
     989                 :                : }
     990                 :                : 
     991                 :            400 : const format cell::format() const
     992                 :                : {
     993         [ -  + ]:            400 :     if (!d_->format_.is_set())
     994                 :                :     {
     995            [ # ]:UBC           0 :         throw invalid_attribute();
     996                 :                :     }
     997                 :                : 
     998         [ +  + ]:CBC         400 :     return xlnt::format(d_->format_);
     999                 :                : }
    1000                 :                : 
    1001                 :              1 : alignment cell::alignment() const
    1002                 :                : {
    1003         [ +  + ]:              1 :     return format().alignment();
    1004                 :                : }
    1005                 :                : 
    1006                 :              1 : border cell::border() const
    1007                 :                : {
    1008         [ +  + ]:              1 :     return format().border();
    1009                 :                : }
    1010                 :                : 
    1011                 :              3 : fill cell::fill() const
    1012                 :                : {
    1013         [ +  + ]:              3 :     return format().fill();
    1014                 :                : }
    1015                 :                : 
    1016                 :             12 : font cell::font() const
    1017                 :                : {
    1018         [ +  + ]:             12 :     return format().font();
    1019                 :                : }
    1020                 :                : 
    1021                 :             17 : number_format cell::number_format() const
    1022                 :                : {
    1023         [ +  + ]:             17 :     return format().number_format();
    1024                 :                : }
    1025                 :                : 
    1026                 :              1 : protection cell::protection() const
    1027                 :                : {
    1028         [ +  + ]:              1 :     return format().protection();
    1029                 :                : }
    1030                 :                : 
    1031                 :            974 : bool cell::has_hyperlink() const
    1032                 :                : {
    1033                 :            974 :     return d_->hyperlink_.is_set();
    1034                 :                : }
    1035                 :                : 
    1036                 :                : // comment
    1037                 :                : 
    1038                 :           1049 : bool cell::has_comment() const
    1039                 :                : {
    1040                 :           1049 :     return d_->comment_.is_set();
    1041                 :                : }
    1042                 :                : 
    1043                 :              1 : void cell::clear_comment()
    1044                 :                : {
    1045         [ +  - ]:              1 :     if (has_comment())
    1046                 :                :     {
    1047      [ +  +  + ]:              1 :         d_->parent_->comments_.erase(reference().to_string());
    1048                 :              1 :         d_->comment_.clear();
    1049                 :                :     }
    1050                 :              1 : }
    1051                 :                : 
    1052                 :             56 : class comment cell::comment() const
    1053                 :                : {
    1054         [ +  + ]:             56 :     if (!has_comment())
    1055                 :                :     {
    1056         [ +  + ]:              6 :         throw xlnt::exception("cell has no comment");
    1057                 :                :     }
    1058                 :                : 
    1059                 :             54 :     return *d_->comment_.get();
    1060                 :                : }
    1061                 :                : 
    1062                 :UBC           0 : void cell::comment(const std::string &text, const std::string &author)
    1063                 :                : {
    1064         [ #  # ]:              0 :     comment(xlnt::comment(text, author));
    1065                 :              0 : }
    1066                 :                : 
    1067                 :CBC           4 : void cell::comment(const std::string &text, const class font &comment_font, const std::string &author)
    1068                 :                : {
    1069      [ +  +  + ]:              4 :     comment(xlnt::comment(xlnt::rich_text(text, comment_font), author));
    1070                 :              4 : }
    1071                 :                : 
    1072                 :             34 : void cell::comment(const class comment &new_comment)
    1073                 :                : {
    1074         [ -  + ]:             34 :     if (has_comment())
    1075                 :                :     {
    1076         [ #  # ]:UBC           0 :         *d_->comment_.get() = new_comment;
    1077                 :                :     }
    1078                 :                :     else
    1079                 :                :     {
    1080   [ +  +  +  + ]:CBC          34 :         d_->parent_->comments_[reference().to_string()] = new_comment;
    1081      [ +  +  + ]:             34 :         d_->comment_.set(&d_->parent_->comments_[reference().to_string()]);
    1082                 :                :     }
    1083                 :                : 
    1084                 :                :     // offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
    1085            [ + ]:             34 :     auto cell_position = anchor();
    1086            [ + ]:             34 :     cell_position.first += static_cast<int>(width()) + 5;
    1087                 :             34 :     cell_position.second += 5;
    1088                 :                : 
    1089         [ +  + ]:             34 :     d_->comment_.get()->position(cell_position.first, cell_position.second);
    1090                 :                : 
    1091         [ +  + ]:             34 :     worksheet().register_comments_in_manifest();
    1092                 :             34 : }
    1093                 :                : 
    1094                 :             34 : double cell::width() const
    1095                 :                : {
    1096         [ +  + ]:             34 :     return worksheet().column_width(column());
    1097                 :                : }
    1098                 :                : 
    1099                 :UBC           0 : double cell::height() const
    1100                 :                : {
    1101         [ #  # ]:              0 :     return worksheet().row_height(row());
    1102                 :                : }
    1103                 :                : 
    1104                 :                : } // namespace xlnt
        

Generated by: LCOV version 2.3.1-beta