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 : 613 : std::string cell::check_string(const std::string &to_check)
170 : : {
171 : : // so we can modify it
172 : 613 : std::string s = to_check;
173 : :
174 [ + + ]: 613 : if (s.size() == 0)
175 : : {
176 : 2 : return s;
177 : : }
178 [ + + ]: 611 : else if (s.size() > 32767)
179 : : {
180 [ + ]: 1 : s = s.substr(0, 32767); // max string length in Excel
181 : : }
182 : :
183 [ + + ]: 68353 : for (char c : s)
184 : : {
185 [ + - + + : 67771 : if (c >= 0 && (c <= 8 || c == 11 || c == 12 || (c >= 14 && c <= 31)))
+ + + + +
+ + + ]
186 : : {
187 [ + ]: 29 : throw illegal_character(c);
188 : : }
189 : : }
190 : :
191 : 582 : return s;
192 : 29 : }
193 : :
194 : 3264 : cell::cell(detail::cell_impl *d)
195 : 3264 : : d_(d)
196 : : {
197 : 3264 : }
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 : 321 : void cell::value(const std::string &s)
252 : : {
253 [ + + + ]: 321 : value(rich_text(check_string(s)));
254 : 292 : }
255 : :
256 : 292 : void cell::value(const rich_text &text)
257 : : {
258 [ + + ]: 292 : check_string(text.plain_text());
259 : :
260 : 292 : d_->type_ = type::shared_string;
261 [ + + ]: 292 : d_->value_numeric_ = static_cast<double>(workbook().add_shared_string(text));
262 : 292 : }
263 : :
264 : 120 : void cell::value(const char *c)
265 : : {
266 [ + + ]: 120 : value(std::string(c));
267 : 120 : }
268 : :
269 : 1 : void cell::value(const cell c)
270 : : {
271 : 1 : d_->type_ = c.d_->type_;
272 : 1 : d_->value_numeric_ = c.d_->value_numeric_;
273 : 1 : d_->value_text_ = c.d_->value_text_;
274 : 1 : d_->hyperlink_ = c.d_->hyperlink_;
275 : 1 : d_->formula_ = c.d_->formula_;
276 : 1 : d_->format_ = c.d_->format_;
277 : 1 : }
278 : :
279 : 3 : void cell::value(const date &d)
280 : : {
281 : 3 : d_->type_ = type::number;
282 : 3 : d_->value_numeric_ = d.to_number(base_date());
283 [ + + ]: 3 : number_format(number_format::date_yyyymmdd2());
284 : 3 : }
285 : :
286 : 5 : void cell::value(const datetime &d)
287 : : {
288 : 5 : d_->type_ = type::number;
289 : 5 : d_->value_numeric_ = d.to_number(base_date());
290 [ + + ]: 5 : number_format(number_format::date_datetime());
291 : 5 : }
292 : :
293 : 2 : void cell::value(const time &t)
294 : : {
295 : 2 : d_->type_ = type::number;
296 : 2 : d_->value_numeric_ = t.to_number();
297 [ + + ]: 2 : number_format(number_format::date_time6());
298 : 2 : }
299 : :
300 : 2 : void cell::value(const timedelta &t)
301 : : {
302 : 2 : d_->type_ = type::number;
303 : 2 : d_->value_numeric_ = t.to_number();
304 [ + + + ]: 2 : number_format(xlnt::number_format("[hh]:mm:ss"));
305 : 2 : }
306 : :
307 : 7 : row_t cell::row() const
308 : : {
309 : 7 : return d_->row_;
310 : : }
311 : :
312 : 39 : column_t cell::column() const
313 : : {
314 : 39 : return d_->column_;
315 : : }
316 : :
317 : 1 : column_t::index_t cell::column_index() const
318 : : {
319 : 1 : return d_->column_.index;
320 : : }
321 : :
322 : 774 : void cell::merged(bool merged)
323 : : {
324 : 774 : d_->is_merged_ = merged;
325 : 774 : }
326 : :
327 :UBC 0 : bool cell::is_merged() const
328 : : {
329 : 0 : return d_->is_merged_;
330 : : }
331 : :
332 :CBC 964 : bool cell::phonetics_visible() const
333 : : {
334 : 964 : return d_->phonetics_visible_;
335 : : }
336 : :
337 : 2 : void cell::show_phonetics(bool phonetics)
338 : : {
339 : 2 : d_->phonetics_visible_ = phonetics;
340 : 2 : }
341 : :
342 : 7 : bool cell::is_date() const
343 : : {
344 : 7 : return data_type() == type::number
345 [ + - ]: 4 : && has_format()
346 [ + + + + : 11 : && number_format().is_date_format();
+ + + + -
- ]
347 : : }
348 : :
349 : 1124 : cell_reference cell::reference() const
350 : : {
351 [ + ]: 1124 : return {d_->column_, d_->row_};
352 : : }
353 : :
354 : 17 : bool cell::compare(const cell &other, bool compare_by_reference) const
355 : : {
356 [ + - ]: 17 : if (compare_by_reference)
357 : : {
358 : 17 : return d_ == other.d_;
359 : : }
360 : : else
361 : : {
362 :UBC 0 : return *d_ == *other.d_;
363 : : }
364 : : }
365 : :
366 :CBC 17 : bool cell::operator==(const cell &comparand) const
367 : : {
368 : 17 : return compare(comparand, true);
369 : : }
370 : :
371 : 2 : bool cell::operator!=(const cell &comparand) const
372 : : {
373 : 2 : return !(*this == comparand);
374 : : }
375 : :
376 : 1 : cell &cell::operator=(const cell &rhs) = default;
377 : :
378 : 62 : hyperlink cell::hyperlink() const
379 : : {
380 [ + + ]: 62 : return xlnt::hyperlink(&d_->hyperlink_.get());
381 : : }
382 : :
383 : 38 : void cell::hyperlink(const std::string &url, const std::string &display)
384 : : {
385 [ + + ]: 38 : if (url.empty())
386 : : {
387 [ + ]: 1 : throw invalid_parameter();
388 : : }
389 : :
390 [ + ]: 37 : auto ws = worksheet();
391 [ + + ]: 37 : auto &manifest = ws.workbook().manifest();
392 : :
393 [ + ]: 37 : d_->hyperlink_ = detail::hyperlink_impl();
394 : :
395 : : // check for existing relationships
396 [ + + ]: 37 : auto relationships = manifest.relationships(ws.path(), relationship_type::hyperlink);
397 [ + ]: 37 : auto relation = std::find_if(relationships.cbegin(), relationships.cend(),
398 : 57 : [&url](xlnt::relationship rel) { return rel.target().path().string() == url; });
399 [ + + ]: 37 : if (relation != relationships.end())
400 : : {
401 [ + + ]: 30 : d_->hyperlink_.get().relationship = *relation;
402 : : }
403 : : else
404 : : { // register a new relationship
405 : : auto rel_id = manifest.register_relationship(
406 [ + + + ]: 14 : uri(ws.path().string()),
407 : : relationship_type::hyperlink,
408 [ + ]: 14 : uri(url),
409 [ + ]: 7 : target_mode::external);
410 : : // TODO: make manifest::register_relationship return the created relationship instead of rel id
411 [ + + + ]: 7 : d_->hyperlink_.get().relationship = manifest.relationship(ws.path(), rel_id);
412 : 7 : }
413 : : // if a value is already present, the display string is ignored
414 [ + + ]: 37 : if (has_value())
415 : : {
416 [ + + ]: 31 : d_->hyperlink_.get().display.set(to_string());
417 : : }
418 : : else
419 : : {
420 [ + + + + ]: 6 : d_->hyperlink_.get().display.set(display.empty() ? url : display);
421 [ + + + ]: 6 : value(hyperlink().display());
422 : : }
423 : 37 : }
424 : :
425 : 4 : void cell::hyperlink(xlnt::cell target, const std::string &display)
426 : : {
427 : : // TODO: should this computed value be a method on a cell?
428 [ + + + + : 4 : const auto cell_address = target.worksheet().title() + "!" + target.reference().to_string();
+ + ]
429 : :
430 [ + ]: 4 : d_->hyperlink_ = detail::hyperlink_impl();
431 [ + ]: 8 : d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
432 [ + + + + : 28 : uri(""), uri(cell_address), target_mode::internal);
+ ]
433 : : // if a value is already present, the display string is ignored
434 [ + + ]: 4 : if (has_value())
435 : : {
436 [ + + ]: 1 : d_->hyperlink_.get().display.set(to_string());
437 : : }
438 : : else
439 : : {
440 [ + + + + ]: 3 : d_->hyperlink_.get().display.set(display.empty() ? cell_address : display);
441 [ + + + ]: 3 : value(hyperlink().display());
442 : : }
443 : 4 : }
444 : :
445 : 3 : void cell::hyperlink(xlnt::range target, const std::string &display)
446 : : {
447 : : // TODO: should this computed value be a method on a cell?
448 [ + + + + : 3 : const auto range_address = target.target_worksheet().title() + "!" + target.reference().to_string();
+ + ]
449 : :
450 [ + ]: 3 : d_->hyperlink_ = detail::hyperlink_impl();
451 [ + ]: 6 : d_->hyperlink_.get().relationship = xlnt::relationship("", relationship_type::hyperlink,
452 [ + + + + : 21 : uri(""), uri(range_address), target_mode::internal);
+ ]
453 : :
454 : : // if a value is already present, the display string is ignored
455 [ + + ]: 3 : if (has_value())
456 : : {
457 [ + + ]: 1 : d_->hyperlink_.get().display.set(to_string());
458 : : }
459 : : else
460 : : {
461 [ + + + + ]: 2 : d_->hyperlink_.get().display.set(display.empty() ? range_address : display);
462 [ + + + ]: 2 : value(hyperlink().display());
463 : : }
464 : 3 : }
465 : :
466 : 17 : void cell::formula(const std::string &formula)
467 : : {
468 [ + + ]: 17 : if (formula.empty())
469 : : {
470 : 1 : return clear_formula();
471 : : }
472 : :
473 [ + + ]: 16 : if (formula[0] == '=')
474 : : {
475 [ + ]: 7 : d_->formula_ = formula.substr(1);
476 : : }
477 : : else
478 : : {
479 : 9 : d_->formula_ = formula;
480 : : }
481 : :
482 [ + + ]: 16 : worksheet().register_calc_chain_in_manifest();
483 : : }
484 : :
485 : 2207 : bool cell::has_formula() const
486 : : {
487 : 2207 : return d_->formula_.is_set();
488 : : }
489 : :
490 : 18 : std::string cell::formula() const
491 : : {
492 : 18 : return d_->formula_.get();
493 : : }
494 : :
495 : 794 : void cell::clear_formula()
496 : : {
497 [ + + ]: 794 : if (has_formula())
498 : : {
499 : 18 : d_->formula_.clear();
500 [ + + ]: 18 : worksheet().garbage_collect_formulae();
501 : : }
502 : 794 : }
503 : :
504 : 21 : std::string cell::error() const
505 : : {
506 [ + + ]: 21 : if (d_->type_ != type::error)
507 : : {
508 [ + + ]: 21 : throw xlnt::exception("called error() when cell type is not error");
509 : : }
510 : 14 : return value<std::string>();
511 : : }
512 : :
513 : 17 : void cell::error(const std::string &error)
514 : : {
515 [ + + + + : 17 : if (error.length() == 0 || error[0] != '#')
+ + ]
516 : : {
517 [ + ]: 2 : throw invalid_data_type();
518 : : }
519 : :
520 : 15 : d_->value_text_.plain_text(error, false);
521 : 15 : d_->type_ = type::error;
522 : 15 : }
523 : :
524 : 1 : cell cell::offset(int column, int row)
525 : : {
526 [ + + + + ]: 1 : return worksheet().cell(reference().make_offset(column, row));
527 : : }
528 : :
529 : 457 : worksheet cell::worksheet()
530 : : {
531 : 457 : return xlnt::worksheet(d_->parent_);
532 : : }
533 : :
534 : 252 : const worksheet cell::worksheet() const
535 : : {
536 : 252 : return xlnt::worksheet(d_->parent_);
537 : : }
538 : :
539 : 347 : workbook cell::workbook()
540 : : {
541 [ + + ]: 347 : return worksheet().workbook();
542 : : }
543 : :
544 : 202 : const workbook cell::workbook() const
545 : : {
546 [ + + ]: 202 : return worksheet().workbook();
547 : : }
548 : :
549 : 35 : std::pair<int, int> cell::anchor() const
550 : : {
551 : 35 : double left = 0;
552 : :
553 [ + + + + : 35 : for (column_t column_index = 1; column_index <= d_->column_ - 1; column_index++)
- + ]
554 : : {
555 [ # # # ]:UBC 0 : left += worksheet().column_width(column_index);
556 : : }
557 : :
558 :CBC 35 : double top = 0;
559 : :
560 [ + + ]: 51 : for (row_t row_index = 1; row_index <= d_->row_ - 1; row_index++)
561 : : {
562 [ + + ]: 16 : top += worksheet().row_height(row_index);
563 : : }
564 : :
565 : 35 : return {static_cast<int>(left), static_cast<int>(top)};
566 : : }
567 : :
568 : 2960 : cell::type cell::data_type() const
569 : : {
570 : 2960 : return d_->type_;
571 : : }
572 : :
573 : 151 : void cell::data_type(type t)
574 : : {
575 : 151 : d_->type_ = t;
576 : 151 : }
577 : :
578 : 47 : number_format cell::computed_number_format() const
579 : : {
580 : 47 : return xlnt::number_format();
581 : : }
582 : :
583 :UBC 0 : font cell::computed_font() const
584 : : {
585 : 0 : return xlnt::font();
586 : : }
587 : :
588 : 0 : fill cell::computed_fill() const
589 : : {
590 : 0 : return xlnt::fill();
591 : : }
592 : :
593 : 0 : border cell::computed_border() const
594 : : {
595 : 0 : return xlnt::border();
596 : : }
597 : :
598 : 0 : alignment cell::computed_alignment() const
599 : : {
600 : 0 : return xlnt::alignment();
601 : : }
602 : :
603 : 0 : protection cell::computed_protection() const
604 : : {
605 [ # ]: 0 : return xlnt::protection();
606 : : }
607 : :
608 :CBC 767 : void cell::clear_value()
609 : : {
610 : 767 : d_->value_numeric_ = 0;
611 : 767 : d_->value_text_.clear();
612 : 767 : d_->type_ = cell::type::empty;
613 : 767 : clear_formula();
614 : 767 : }
615 : :
616 : : template <>
617 : 7 : bool cell::value() const
618 : : {
619 : 7 : return d_->value_numeric_ != 0.0;
620 : : }
621 : :
622 : : template <>
623 : 24 : int cell::value() const
624 : : {
625 : 24 : return static_cast<int>(d_->value_numeric_);
626 : : }
627 : :
628 : : template <>
629 : 1 : long long int cell::value() const
630 : : {
631 : 1 : return static_cast<long long int>(d_->value_numeric_);
632 : : }
633 : :
634 : : template <>
635 : 1 : unsigned int cell::value() const
636 : : {
637 : 1 : return static_cast<unsigned int>(d_->value_numeric_);
638 : : }
639 : :
640 : : template <>
641 : 1 : unsigned long long cell::value() const
642 : : {
643 : 1 : return static_cast<unsigned long long>(d_->value_numeric_);
644 : : }
645 : :
646 : : template <>
647 : 1 : float cell::value() const
648 : : {
649 : 1 : return static_cast<float>(d_->value_numeric_);
650 : : }
651 : :
652 : : template <>
653 : 67 : double cell::value() const
654 : : {
655 : 67 : return static_cast<double>(d_->value_numeric_);
656 : : }
657 : :
658 : : template <>
659 : 3 : time cell::value() const
660 : : {
661 : 3 : return time::from_number(d_->value_numeric_);
662 : : }
663 : :
664 : : template <>
665 :UBC 0 : datetime cell::value() const
666 : : {
667 : 0 : return datetime::from_number(d_->value_numeric_, base_date());
668 : : }
669 : :
670 : : template <>
671 : 0 : date cell::value() const
672 : : {
673 : 0 : return date::from_number(static_cast<int>(d_->value_numeric_), base_date());
674 : : }
675 : :
676 : : template <>
677 : 0 : timedelta cell::value() const
678 : : {
679 : 0 : return timedelta::from_number(d_->value_numeric_);
680 : : }
681 : :
682 :CBC 1 : void cell::alignment(const class alignment &alignment_)
683 : : {
684 [ - + - + : 1 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + - -
- ]
685 [ + + + ]: 1 : format(new_format.alignment(alignment_, optional<bool>(true)));
686 : 1 : }
687 : :
688 : 1 : void cell::border(const class border &border_)
689 : : {
690 [ - + - + : 1 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + - -
- ]
691 [ + + + ]: 1 : format(new_format.border(border_, optional<bool>(true)));
692 : 1 : }
693 : :
694 : 13 : void cell::fill(const class fill &fill_)
695 : : {
696 [ + + + + : 13 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + + -
- ]
697 [ + + + ]: 13 : format(new_format.fill(fill_, optional<bool>(true)));
698 : 13 : }
699 : :
700 : 23 : void cell::font(const class font &font_)
701 : : {
702 [ + + + + : 23 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + + -
- ]
703 [ + + + ]: 23 : format(new_format.font(font_, optional<bool>(true)));
704 : 23 : }
705 : :
706 : 21 : void cell::number_format(const class number_format &number_format_)
707 : : {
708 [ + + + + : 21 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + + -
- ]
709 [ + + + ]: 21 : format(new_format.number_format(number_format_, optional<bool>(true)));
710 : 21 : }
711 : :
712 : 1 : void cell::protection(const class protection &protection_)
713 : : {
714 [ - + - + : 1 : auto new_format = has_format() ? modifiable_format() : workbook().create_format();
+ + - -
- ]
715 [ + + + ]: 1 : format(new_format.protection(protection_, optional<bool>(true)));
716 : 1 : }
717 : :
718 : : template <>
719 : 211 : std::string cell::value() const
720 : : {
721 [ + + ]: 211 : return value<rich_text>().plain_text();
722 : : }
723 : :
724 : : template <>
725 : 214 : rich_text cell::value() const
726 : : {
727 [ + + ]: 214 : if (data_type() == cell::type::shared_string)
728 : : {
729 [ + + + ]: 189 : return workbook().shared_strings(static_cast<std::size_t>(d_->value_numeric_));
730 : : }
731 : :
732 : 25 : return d_->value_text_;
733 : : }
734 : :
735 : 112 : bool cell::has_value() const
736 : : {
737 : 112 : return d_->type_ != cell::type::empty;
738 : : }
739 : :
740 : 47 : std::string cell::to_string() const
741 : : {
742 [ + ]: 47 : auto nf = computed_number_format();
743 : :
744 [ + + + + : 47 : switch (data_type())
- ]
745 : : {
746 : 2 : case cell::type::empty:
747 [ + ]: 4 : return "";
748 : 5 : case cell::type::date:
749 : : case cell::type::number:
750 [ + + ]: 5 : return nf.format(value<double>(), base_date());
751 : 36 : case cell::type::inline_string:
752 : : case cell::type::shared_string:
753 : : case cell::type::formula_string:
754 : : case cell::type::error:
755 [ + + ]: 36 : return nf.format(value<std::string>());
756 : 4 : case cell::type::boolean:
757 [ + + + ]: 8 : return value<double>() == 0.0 ? "FALSE" : "TRUE";
758 : : }
759 : :
760 [ # ]:UBC 0 : return "";
761 :CBC 47 : }
762 : :
763 : 1051 : bool cell::has_format() const
764 : : {
765 : 1051 : return d_->format_.is_set();
766 : : }
767 : :
768 : 102 : void cell::format(const class format new_format)
769 : : {
770 : 102 : d_->format_ = new_format.d_;
771 : 102 : }
772 : :
773 : 13 : calendar cell::base_date() const
774 : : {
775 [ + + ]: 13 : return workbook().base_date();
776 : : }
777 : :
778 : 4 : bool operator==(std::nullptr_t, const cell &cell)
779 : : {
780 : 4 : return cell.data_type() == cell::type::empty;
781 : : }
782 : :
783 : 2 : bool operator==(const cell &cell, std::nullptr_t)
784 : : {
785 : 2 : return nullptr == cell;
786 : : }
787 : :
788 :UBC 0 : bool operator!=(std::nullptr_t, const cell &cell)
789 : : {
790 : 0 : return !(nullptr == cell);
791 : : }
792 : :
793 : 0 : bool operator!=(const cell &cell, std::nullptr_t)
794 : : {
795 : 0 : return nullptr != cell;
796 : : }
797 : :
798 :CBC 6 : std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
799 : : {
800 [ + + ]: 6 : return stream << cell.to_string();
801 : : }
802 : :
803 : 23 : void cell::value(const std::string &value_string, bool infer_type)
804 : : {
805 [ + ]: 23 : value(value_string);
806 : :
807 [ + - - + : 23 : if (!infer_type || value_string.empty())
- + ]
808 : : {
809 : 9 : return;
810 : : }
811 : :
812 [ + + + + : 23 : if (value_string.front() == '=' && value_string.size() > 1)
+ + ]
813 : : {
814 [ + ]: 2 : formula(value_string);
815 : 2 : return;
816 : : }
817 : :
818 [ + + + - : 21 : if (value_string.front() == '#' && value_string.size() > 1)
+ + ]
819 : : {
820 [ + ]: 7 : error(value_string);
821 : 7 : return;
822 : : }
823 : :
824 [ + ]: 14 : auto percentage = cast_percentage(value_string);
825 : :
826 [ + + ]: 14 : if (percentage.first)
827 : : {
828 : 1 : d_->value_numeric_ = percentage.second;
829 : 1 : d_->type_ = cell::type::number;
830 [ + + ]: 1 : number_format(xlnt::number_format::percentage());
831 : : }
832 : : else
833 : : {
834 [ + ]: 13 : auto time = cast_time(value_string);
835 : :
836 [ + + ]: 13 : if (time.first)
837 : : {
838 : 3 : d_->type_ = cell::type::number;
839 [ + + ]: 3 : number_format(number_format::date_time6());
840 [ + ]: 3 : d_->value_numeric_ = time.second.to_number();
841 : : }
842 : : else
843 : : {
844 [ + ]: 10 : auto numeric = cast_numeric(value_string);
845 : :
846 [ + + ]: 10 : if (numeric.first)
847 : : {
848 : 8 : d_->value_numeric_ = numeric.second;
849 : 8 : d_->type_ = cell::type::number;
850 : : }
851 : : }
852 : : }
853 : : }
854 : :
855 : 2 : void cell::clear_format()
856 : : {
857 [ + - ]: 2 : if (d_->format_.is_set())
858 : 2 : d_->format_.clear();
859 : 2 : }
860 : :
861 : 2 : void cell::clear_style()
862 : : {
863 [ + - ]: 2 : if (has_format())
864 : : {
865 [ + + ]: 2 : modifiable_format().clear_style();
866 : : }
867 : 2 : }
868 : :
869 : 4 : void cell::style(const class style &new_style)
870 : : {
871 [ + + + + : 4 : auto new_format = has_format() ? format() : workbook().create_format();
+ + + -
- ]
872 : :
873 [ + + ]: 4 : new_format.border(new_style.border());
874 [ + + ]: 4 : new_format.fill(new_style.fill());
875 [ + + ]: 4 : new_format.font(new_style.font());
876 [ + + ]: 4 : new_format.number_format(new_style.number_format());
877 : :
878 [ + + + ]: 4 : format(new_format.style(new_style));
879 : 4 : }
880 : :
881 : 2 : void cell::style(const std::string &style_name)
882 : : {
883 [ + + + ]: 3 : style(workbook().style(style_name));
884 : 1 : }
885 : :
886 : 7 : style cell::style()
887 : : {
888 [ + - + + : 7 : if (!has_format() || !format().has_style())
+ + + - +
+ - - ]
889 : : {
890 [ + ]: 1 : throw invalid_attribute();
891 : : }
892 : :
893 [ + ]: 6 : auto f = format();
894 : :
895 [ + ]: 12 : return f.style();
896 : 6 : }
897 : :
898 :UBC 0 : const style cell::style() const
899 : : {
900 [ # # # # : 0 : if (!has_format() || !format().has_style())
# # # # #
# # # ]
901 : : {
902 [ # ]: 0 : throw invalid_attribute();
903 : : }
904 : :
905 [ # # ]: 0 : return format().style();
906 : : }
907 : :
908 :CBC 5 : bool cell::has_style() const
909 : : {
910 [ + + + + : 5 : return has_format() && format().has_style();
+ + + + -
- ]
911 : : }
912 : :
913 : 11 : format cell::modifiable_format()
914 : : {
915 [ - + ]: 11 : if (!d_->format_.is_set())
916 : : {
917 [ # ]:UBC 0 : throw invalid_attribute();
918 : : }
919 : :
920 [ + + ]:CBC 11 : return xlnt::format(d_->format_);
921 : : }
922 : :
923 : 391 : const format cell::format() const
924 : : {
925 [ - + ]: 391 : if (!d_->format_.is_set())
926 : : {
927 [ # ]:UBC 0 : throw invalid_attribute();
928 : : }
929 : :
930 [ + + ]:CBC 391 : return xlnt::format(d_->format_);
931 : : }
932 : :
933 : 1 : alignment cell::alignment() const
934 : : {
935 [ + + ]: 1 : return format().alignment();
936 : : }
937 : :
938 : 1 : border cell::border() const
939 : : {
940 [ + + ]: 1 : return format().border();
941 : : }
942 : :
943 : 3 : fill cell::fill() const
944 : : {
945 [ + + ]: 3 : return format().fill();
946 : : }
947 : :
948 : 7 : font cell::font() const
949 : : {
950 [ + + ]: 7 : return format().font();
951 : : }
952 : :
953 : 17 : number_format cell::number_format() const
954 : : {
955 [ + + ]: 17 : return format().number_format();
956 : : }
957 : :
958 : 1 : protection cell::protection() const
959 : : {
960 [ + + ]: 1 : return format().protection();
961 : : }
962 : :
963 : 967 : bool cell::has_hyperlink() const
964 : : {
965 : 967 : return d_->hyperlink_.is_set();
966 : : }
967 : :
968 : : // comment
969 : :
970 : 1049 : bool cell::has_comment() const
971 : : {
972 : 1049 : return d_->comment_.is_set();
973 : : }
974 : :
975 : 1 : void cell::clear_comment()
976 : : {
977 [ + - ]: 1 : if (has_comment())
978 : : {
979 [ + + + ]: 1 : d_->parent_->comments_.erase(reference().to_string());
980 : 1 : d_->comment_.clear();
981 : : }
982 : 1 : }
983 : :
984 : 56 : class comment cell::comment() const
985 : : {
986 [ + + ]: 56 : if (!has_comment())
987 : : {
988 [ + + ]: 6 : throw xlnt::exception("cell has no comment");
989 : : }
990 : :
991 : 54 : return *d_->comment_.get();
992 : : }
993 : :
994 :UBC 0 : void cell::comment(const std::string &text, const std::string &author)
995 : : {
996 [ # # ]: 0 : comment(xlnt::comment(text, author));
997 : 0 : }
998 : :
999 :CBC 4 : void cell::comment(const std::string &text, const class font &comment_font, const std::string &author)
1000 : : {
1001 [ + + + ]: 4 : comment(xlnt::comment(xlnt::rich_text(text, comment_font), author));
1002 : 4 : }
1003 : :
1004 : 34 : void cell::comment(const class comment &new_comment)
1005 : : {
1006 [ - + ]: 34 : if (has_comment())
1007 : : {
1008 [ # # ]:UBC 0 : *d_->comment_.get() = new_comment;
1009 : : }
1010 : : else
1011 : : {
1012 [ + + + + ]:CBC 34 : d_->parent_->comments_[reference().to_string()] = new_comment;
1013 [ + + + ]: 34 : d_->comment_.set(&d_->parent_->comments_[reference().to_string()]);
1014 : : }
1015 : :
1016 : : // offset comment 5 pixels down and 5 pixels right of the top right corner of the cell
1017 [ + ]: 34 : auto cell_position = anchor();
1018 [ + ]: 34 : cell_position.first += static_cast<int>(width()) + 5;
1019 : 34 : cell_position.second += 5;
1020 : :
1021 [ + + ]: 34 : d_->comment_.get()->position(cell_position.first, cell_position.second);
1022 : :
1023 [ + + ]: 34 : worksheet().register_comments_in_manifest();
1024 : 34 : }
1025 : :
1026 : 34 : double cell::width() const
1027 : : {
1028 [ + + ]: 34 : return worksheet().column_width(column());
1029 : : }
1030 : :
1031 :UBC 0 : double cell::height() const
1032 : : {
1033 [ # # ]: 0 : return worksheet().row_height(row());
1034 : : }
1035 : :
1036 : : } // namespace xlnt
|