1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8 #include "xlsx_conditional_format_context.hpp"
9 #include "xlsx_helper.hpp"
10 #include "xlsx_types.hpp"
11 #include "ooxml_token_constants.hpp"
12 #include "ooxml_namespace_types.hpp"
13
14 #include "orcus/global.hpp"
15 #include "orcus/exception.hpp"
16 #include "orcus/spreadsheet/import_interface.hpp"
17 #include "orcus/measurement.hpp"
18
19 #include <mdds/sorted_string_map.hpp>
20 #include <mdds/global.hpp>
21
22 namespace orcus {
23
24 namespace {
25
26 enum xlsx_cond_format_type
27 {
28 none = 0,
29 expression,
30 cellIs,
31 colorScale,
32 dataBar,
33 iconSet,
34 top10,
35 uniqueValues,
36 duplicateValues,
37 containsText,
38 notContainsText,
39 beginsWith,
40 endsWith,
41 containsBlanks,
42 notContainsBlanks,
43 containsErrors,
44 notContainsErrors,
45 timePeriod,
46 aboveAverage
47 };
48
49 enum xlsx_cond_format_operator
50 {
51 operator_default = 0,
52 operator_beginsWith,
53 operator_between,
54 operator_containsText,
55 operator_endsWith,
56 operator_equal,
57 operator_greaterThan,
58 operator_greaterThanOrEqual,
59 operator_lessThan,
60 operator_lessThanOrEqual,
61 operator_notBetween,
62 operator_notContains,
63 operator_notEqual
64 };
65
66 enum xlsx_cond_format_date
67 {
68 date_default = 0,
69 date_last7Days,
70 date_lastMonth,
71 date_lastWeek,
72 date_nextMonth,
73 date_thisMonth,
74 date_thisWeek,
75 date_today,
76 date_tomorrow,
77 date_yesterday
78 };
79
80 enum xlsx_cond_format_boolean
81 {
82 boolean_default = 0,
83 boolean_true,
84 boolean_false
85 };
86
87 typedef mdds::sorted_string_map<xlsx_cond_format_type> cond_format_type_map;
88
89 typedef mdds::sorted_string_map<xlsx_cond_format_boolean> cond_format_boolean_map;
90
91 typedef mdds::sorted_string_map<xlsx_cond_format_operator> cond_format_operator_map;
92
93 typedef mdds::sorted_string_map<xlsx_cond_format_date> cond_format_date_map;
94
95 cond_format_type_map::entry cond_format_type_entries[] =
96 {
97 { MDDS_ASCII("aboveAverage"), aboveAverage },
98 { MDDS_ASCII("beginsWith"), beginsWith },
99 { MDDS_ASCII("cellIs"), cellIs },
100 { MDDS_ASCII("colorScale"), colorScale },
101 { MDDS_ASCII("containsBlanks"), containsBlanks },
102 { MDDS_ASCII("containsErrors"), containsErrors },
103 { MDDS_ASCII("containsText"), containsText },
104 { MDDS_ASCII("dataBar"), dataBar },
105 { MDDS_ASCII("duplicateValues"), duplicateValues },
106 { MDDS_ASCII("endsWith"), endsWith },
107 { MDDS_ASCII("expression"), expression },
108 { MDDS_ASCII("iconSet"), iconSet },
109 { MDDS_ASCII("notContainsErrors"), notContainsErrors },
110 { MDDS_ASCII("notContainsText"), notContainsText },
111 { MDDS_ASCII("timePeriod"), timePeriod },
112 { MDDS_ASCII("top10"), top10 },
113 { MDDS_ASCII("uniqueValues"), uniqueValues }
114 };
115
116 cond_format_operator_map::entry cond_format_operator_entries[] =
117 {
118 { MDDS_ASCII("beginsWith"), operator_beginsWith },
119 { MDDS_ASCII("between"), operator_between },
120 { MDDS_ASCII("containsText"), operator_containsText },
121 { MDDS_ASCII("endsWith"), operator_endsWith },
122 { MDDS_ASCII("equal"), operator_equal },
123 { MDDS_ASCII("greaterThan"), operator_greaterThan },
124 { MDDS_ASCII("greaterThanOrEqual"), operator_greaterThanOrEqual },
125 { MDDS_ASCII("lessThan"), operator_lessThan },
126 { MDDS_ASCII("lessThanOrEqual"), operator_lessThanOrEqual },
127 { MDDS_ASCII("notBetween"), operator_notBetween },
128 { MDDS_ASCII("notContains"), operator_notContains },
129 { MDDS_ASCII("notEqual"), operator_notEqual }
130 };
131
132 cond_format_date_map::entry cond_format_date_entries[] =
133 {
134 { MDDS_ASCII("last7Days"), date_last7Days },
135 { MDDS_ASCII("lastMonth"), date_lastMonth },
136 { MDDS_ASCII("lastWeek"), date_lastWeek },
137 { MDDS_ASCII("nextMonth"), date_nextMonth },
138 { MDDS_ASCII("thisMonth"), date_thisMonth },
139 { MDDS_ASCII("thisWeek"), date_thisWeek },
140 { MDDS_ASCII("today"), date_today },
141 { MDDS_ASCII("tomorrow"), date_tomorrow },
142 { MDDS_ASCII("yesterday"), date_yesterday }
143 };
144
145 cond_format_boolean_map::entry cond_format_boolean_entries[] =
146 {
147 { MDDS_ASCII("0"), boolean_false },
148 { MDDS_ASCII("1"), boolean_true },
149 { MDDS_ASCII("false"), boolean_true },
150 { MDDS_ASCII("true"), boolean_false }
151 };
152
parse_boolean_flag(const xml_token_attr_t & attr,bool default_value)153 bool parse_boolean_flag(const xml_token_attr_t& attr, bool default_value)
154 {
155 static const cond_format_boolean_map boolean_map(cond_format_boolean_entries, sizeof(cond_format_boolean_entries)/sizeof(cond_format_boolean_entries[0]), boolean_default);
156 xlsx_cond_format_boolean val = boolean_map.find(attr.value.get(), attr.value.size());
157 switch (val)
158 {
159 case boolean_default:
160 return default_value;
161 break;
162 case boolean_true:
163 return true;
164 break;
165 case boolean_false:
166 return false;
167 break;
168 }
169
170 return default_value;
171 }
172
173 struct cfRule_attr_parser : public std::unary_function<xml_token_attr_t, void>
174 {
175
cfRule_attr_parserorcus::__anon82b4a4060111::cfRule_attr_parser176 cfRule_attr_parser(spreadsheet::iface::import_conditional_format& cond_format):
177 m_cond_format(cond_format),
178 m_type(none),
179 m_operator(operator_default),
180 m_date(date_default),
181 m_above_average(true),
182 m_equal_average(false),
183 m_percent(false),
184 m_bottom(false)
185 {
186 }
187
operator ()orcus::__anon82b4a4060111::cfRule_attr_parser188 void operator()(const xml_token_attr_t& attr)
189 {
190 switch(attr.name)
191 {
192 case XML_type:
193 {
194 cond_format_type_map type_map(cond_format_type_entries, sizeof(cond_format_type_entries)/sizeof(cond_format_type_entries[0]), none);
195 m_type = type_map.find(attr.value.get(), attr.value.size());
196 }
197 break;
198 case XML_dxfId:
199 {
200 // TODO: actually we need to translate between dxf id and xf id
201 size_t dxf_id = to_long(attr.value);
202 m_cond_format.set_xf_id(dxf_id);
203 }
204 break;
205 case XML_aboveAverage:
206 {
207 m_above_average = parse_boolean_flag(attr, true);
208 }
209 break;
210 case XML_percent:
211 m_percent = parse_boolean_flag(attr, false);
212 break;
213 case XML_bottom:
214 m_bottom = parse_boolean_flag(attr, false);
215 break;
216 case XML_operator:
217 {
218 cond_format_operator_map operator_map(cond_format_operator_entries, sizeof(cond_format_operator_entries)/sizeof(cond_format_operator_entries[0]), operator_default);
219 m_operator = operator_map.find(attr.value.get(), attr.value.size());
220 }
221 break;
222 case XML_text:
223 // do we need to worry about the transient flag here?
224 m_text = attr.value;
225 break;
226 case XML_timePeriod:
227 {
228 cond_format_date_map date_map(cond_format_date_entries, sizeof(cond_format_date_entries)/sizeof(cond_format_date_entries[0]), date_default);
229 m_date = date_map.find(attr.value.get(), attr.value.size());
230 }
231 break;
232 case XML_rank:
233 // do we need to worry about the transient flag here?
234 m_rank = attr.value;
235 break;
236 case XML_stdDev:
237 // do we need to worry about the transient flag here?
238 m_std_dev = attr.value;
239 break;
240 case XML_equalAverage:
241 m_equal_average = parse_boolean_flag(attr, false);
242 break;
243 default:
244 break;
245 }
246 }
247
set_typeorcus::__anon82b4a4060111::cfRule_attr_parser248 void set_type()
249 {
250 switch (m_type)
251 {
252 case expression:
253 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
254 m_cond_format.set_operator(spreadsheet::condition_operator_t::expression);
255 break;
256 case cellIs:
257 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
258 m_cond_format.set_operator(spreadsheet::condition_operator_t::expression);
259 switch (m_operator)
260 {
261 case operator_beginsWith:
262 m_cond_format.set_operator(spreadsheet::condition_operator_t::begins_with);
263 break;
264 case operator_between:
265 m_cond_format.set_operator(spreadsheet::condition_operator_t::between);
266 break;
267 case operator_containsText:
268 m_cond_format.set_operator(spreadsheet::condition_operator_t::contains);
269 break;
270 case operator_endsWith:
271 m_cond_format.set_operator(spreadsheet::condition_operator_t::ends_with);
272 break;
273 case operator_equal:
274 m_cond_format.set_operator(spreadsheet::condition_operator_t::equal);
275 break;
276 case operator_greaterThan:
277 m_cond_format.set_operator(spreadsheet::condition_operator_t::greater);
278 break;
279 case operator_greaterThanOrEqual:
280 m_cond_format.set_operator(spreadsheet::condition_operator_t::greater_equal);
281 break;
282 case operator_lessThan:
283 m_cond_format.set_operator(spreadsheet::condition_operator_t::less);
284 break;
285 case operator_lessThanOrEqual:
286 m_cond_format.set_operator(spreadsheet::condition_operator_t::less_equal);
287 break;
288 case operator_notBetween:
289 m_cond_format.set_operator(spreadsheet::condition_operator_t::not_between);
290 break;
291 case operator_notContains:
292 m_cond_format.set_operator(spreadsheet::condition_operator_t::not_contains);
293 break;
294 case operator_notEqual:
295 m_cond_format.set_operator(spreadsheet::condition_operator_t::not_equal);
296 break;
297 default:
298 break;
299 }
300 break;
301 case colorScale:
302 m_cond_format.set_type(spreadsheet::conditional_format_t::colorscale);
303 break;
304 case dataBar:
305 m_cond_format.set_type(spreadsheet::conditional_format_t::databar);
306 break;
307 case iconSet:
308 m_cond_format.set_type(spreadsheet::conditional_format_t::iconset);
309 break;
310 case top10:
311 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
312 if (m_bottom)
313 {
314 m_cond_format.set_operator(spreadsheet::condition_operator_t::bottom_n);
315 }
316 else
317 {
318 m_cond_format.set_operator(spreadsheet::condition_operator_t::top_n);
319 }
320 m_cond_format.set_formula(m_rank.get(), m_rank.size());
321 break;
322 case uniqueValues:
323 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
324 m_cond_format.set_operator(spreadsheet::condition_operator_t::unique);
325 break;
326 case duplicateValues:
327 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
328 m_cond_format.set_operator(spreadsheet::condition_operator_t::duplicate);
329 break;
330 case containsText:
331 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
332 m_cond_format.set_operator(spreadsheet::condition_operator_t::contains);
333 m_cond_format.set_formula(m_text.get(), m_text.size());
334 break;
335 case notContainsText:
336 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
337 m_cond_format.set_operator(spreadsheet::condition_operator_t::not_contains);
338 m_cond_format.set_formula(m_text.get(), m_text.size());
339 break;
340 case beginsWith:
341 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
342 m_cond_format.set_operator(spreadsheet::condition_operator_t::begins_with);
343 m_cond_format.set_formula(m_text.get(), m_text.size());
344 break;
345 case endsWith:
346 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
347 m_cond_format.set_operator(spreadsheet::condition_operator_t::ends_with);
348 m_cond_format.set_formula(m_text.get(), m_text.size());
349 break;
350 case containsBlanks:
351 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
352 m_cond_format.set_operator(spreadsheet::condition_operator_t::contains_blanks);
353 break;
354 case containsErrors:
355 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
356 m_cond_format.set_operator(spreadsheet::condition_operator_t::contains_error);
357 break;
358 case notContainsErrors:
359 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
360 m_cond_format.set_operator(spreadsheet::condition_operator_t::contains_no_error);
361 break;
362 case timePeriod:
363 m_cond_format.set_type(spreadsheet::conditional_format_t::date);
364 switch (m_date)
365 {
366 case date_last7Days:
367 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::last_7_days);
368 break;
369 case date_lastMonth:
370 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::last_month);
371 break;
372 case date_lastWeek:
373 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::last_week);
374 break;
375 case date_nextMonth:
376 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::next_month);
377 break;
378 case date_thisMonth:
379 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::this_month);
380 break;
381 case date_thisWeek:
382 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::this_week);
383 break;
384 case date_today:
385 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::today);
386 break;
387 case date_tomorrow:
388 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::tomorrow);
389 break;
390 case date_yesterday:
391 m_cond_format.set_date(orcus::spreadsheet::condition_date_t::yesterday);
392 break;
393 default:
394 break;
395 }
396 break;
397 case aboveAverage:
398 m_cond_format.set_type(spreadsheet::conditional_format_t::condition);
399 if (!m_std_dev.empty())
400 {
401 // TODO: we need a way to mark that as std dev in the interfaces
402 m_cond_format.set_formula(m_std_dev.get(), m_std_dev.size());
403 }
404 if (m_above_average)
405 {
406 if (m_equal_average)
407 {
408 m_cond_format.set_operator(spreadsheet::condition_operator_t::above_equal_average);
409 }
410 else
411 {
412 m_cond_format.set_operator(spreadsheet::condition_operator_t::above_average);
413 }
414 }
415 else
416 {
417 if (m_equal_average)
418 {
419 m_cond_format.set_operator(spreadsheet::condition_operator_t::below_equal_average);
420 }
421 else
422 {
423 m_cond_format.set_operator(spreadsheet::condition_operator_t::below_average);
424 }
425 }
426 break;
427 default:
428 break;
429 }
430 }
431
432 private:
433 spreadsheet::iface::import_conditional_format& m_cond_format;
434 xlsx_cond_format_type m_type;
435 xlsx_cond_format_operator m_operator;
436 xlsx_cond_format_date m_date;
437 bool m_above_average;
438 bool m_equal_average;
439 bool m_percent;
440 bool m_bottom;
441 pstring m_text;
442 pstring m_std_dev;
443 pstring m_rank;
444 };
445
446 struct conditional_formatting_attr_parser : public std::unary_function<xml_token_attr_t, void>
447 {
conditional_formatting_attr_parserorcus::__anon82b4a4060111::conditional_formatting_attr_parser448 conditional_formatting_attr_parser(spreadsheet::iface::import_conditional_format& cond_format):
449 m_cond_format(cond_format)
450 {
451 }
452
operator ()orcus::__anon82b4a4060111::conditional_formatting_attr_parser453 void operator()(const xml_token_attr_t& attr)
454 {
455 switch (attr.name)
456 {
457 case XML_sqref:
458 m_cond_format.set_range(attr.value.get(), attr.value.size());
459 break;
460 default:
461 break;
462 }
463 }
464
465 private:
466 spreadsheet::iface::import_conditional_format& m_cond_format;
467 };
468
469 enum xlsx_cond_format_cfvo_type
470 {
471 cfvo_default = 0,
472 cfvo_num,
473 cfvo_percent,
474 cfvo_max,
475 cfvo_min,
476 cfvo_formula,
477 cfvo_percentile
478 };
479
480 typedef mdds::sorted_string_map<xlsx_cond_format_cfvo_type> cond_format_cfvo_type_map;
481
482 cond_format_cfvo_type_map::entry cond_format_cfvo_entries[] =
483 {
484 { MDDS_ASCII("num"), cfvo_num },
485 { MDDS_ASCII("percent"), cfvo_percent },
486 { MDDS_ASCII("max"), cfvo_max },
487 { MDDS_ASCII("min"), cfvo_min },
488 { MDDS_ASCII("formula"), cfvo_formula },
489 { MDDS_ASCII("percentile"), cfvo_percentile },
490 };
491
492 }
493
494 struct cfvo_values
495 {
cfvo_valuesorcus::cfvo_values496 cfvo_values():
497 m_include_equal(true),
498 m_type(cfvo_default)
499 {
500 }
501
502 bool m_include_equal;
503 xlsx_cond_format_cfvo_type m_type;
504 pstring m_value;
505 };
506
507 namespace {
508
509 struct cfvo_attr_parser : public std::unary_function<xml_token_attr_t, void>
510 {
cfvo_attr_parserorcus::__anon82b4a4060211::cfvo_attr_parser511 cfvo_attr_parser(string_pool& pool):
512 m_string_pool(pool)
513 {
514 }
515
operator ()orcus::__anon82b4a4060211::cfvo_attr_parser516 void operator()(const xml_token_attr_t& attr)
517 {
518 switch (attr.name)
519 {
520 case XML_gte:
521 m_values.m_include_equal = parse_boolean_flag(attr, true);
522 break;
523 case XML_type:
524 {
525 cond_format_cfvo_type_map cfvo_type_map(cond_format_cfvo_entries, sizeof(cond_format_cfvo_entries)/sizeof(cond_format_cfvo_entries[0]), cfvo_default);
526 m_values.m_type = cfvo_type_map.find(attr.value.get(), attr.value.size());
527 }
528 break;
529 case XML_val:
530 if (attr.transient)
531 {
532 m_values.m_value = m_string_pool.intern(attr.value).first;
533 }
534 else
535 {
536 m_values.m_value = attr.value;
537 }
538 break;
539 default:
540 break;
541 }
542 }
543
get_valuesorcus::__anon82b4a4060211::cfvo_attr_parser544 cfvo_values get_values()
545 {
546 return m_values;
547 }
548
549 private:
550 cfvo_values m_values;
551 string_pool& m_string_pool;
552 };
553
554 struct data_bar_attr_parser : public std::unary_function<xml_token_attr_t, void>
555 {
data_bar_attr_parserorcus::__anon82b4a4060211::data_bar_attr_parser556 data_bar_attr_parser():
557 m_show_value(true),
558 m_min_length(10),
559 m_max_length(90)
560 {
561 }
562
operator ()orcus::__anon82b4a4060211::data_bar_attr_parser563 void operator()(const xml_token_attr_t& attr)
564 {
565 switch (attr.name)
566 {
567 case XML_showValue:
568 m_show_value = parse_boolean_flag(attr, true);
569 break;
570 case XML_maxLength:
571 m_max_length = to_long(attr.value);
572 break;
573 case XML_minLength:
574 m_min_length = to_long(attr.value);
575 break;
576 default:
577 break;
578 }
579 }
580
import_dataorcus::__anon82b4a4060211::data_bar_attr_parser581 void import_data(spreadsheet::iface::import_conditional_format& cond_format)
582 {
583 cond_format.set_show_value(m_show_value);
584 cond_format.set_min_databar_length(m_min_length);
585 cond_format.set_max_databar_length(m_max_length);
586 }
587
588 private:
589 bool m_show_value;
590 size_t m_min_length;
591 size_t m_max_length;
592 };
593
594 struct icon_set_attr_parser : public std::unary_function<xml_token_attr_t, void>
595 {
icon_set_attr_parserorcus::__anon82b4a4060211::icon_set_attr_parser596 icon_set_attr_parser():
597 m_reverse(false),
598 m_percent(true),
599 m_show_value(true),
600 icon_name("3Arrows")
601 {
602 }
603
operator ()orcus::__anon82b4a4060211::icon_set_attr_parser604 void operator()(const xml_token_attr_t& attr)
605 {
606 switch (attr.name)
607 {
608 case XML_iconSet:
609 icon_name = attr.value;
610 break;
611 case XML_percent:
612 m_percent = parse_boolean_flag(attr, true);
613 break;
614 case XML_reverse:
615 m_reverse = parse_boolean_flag(attr, false);
616 break;
617 case XML_showValue:
618 m_show_value = parse_boolean_flag(attr, true);
619 break;
620 default:
621 break;
622 }
623 }
624
import_dataorcus::__anon82b4a4060211::icon_set_attr_parser625 void import_data(spreadsheet::iface::import_conditional_format& cond_format)
626 {
627 cond_format.set_show_value(m_show_value);
628 cond_format.set_iconset_reverse(m_reverse);
629 cond_format.set_icon_name(icon_name.get(), icon_name.size());
630 }
631
632 private:
633 bool m_reverse;
634 bool m_percent;
635 bool m_show_value;
636 pstring icon_name;
637 };
638
639 }
640
xlsx_conditional_format_context(session_context & session_cxt,const tokens & tokens,spreadsheet::iface::import_conditional_format & import_cond_format)641 xlsx_conditional_format_context::xlsx_conditional_format_context(
642 session_context& session_cxt, const tokens& tokens,
643 spreadsheet::iface::import_conditional_format& import_cond_format):
644 xml_context_base(session_cxt, tokens),
645 m_cond_format(import_cond_format)
646 {
647 }
648
~xlsx_conditional_format_context()649 xlsx_conditional_format_context::~xlsx_conditional_format_context()
650 {
651 }
652
can_handle_element(xmlns_id_t,xml_token_t) const653 bool xlsx_conditional_format_context::can_handle_element(xmlns_id_t /*ns*/, xml_token_t /*name*/) const
654 {
655 return true;
656 }
657
create_child_context(xmlns_id_t,xml_token_t)658 xml_context_base* xlsx_conditional_format_context::create_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/)
659 {
660 return nullptr;
661 }
662
end_child_context(xmlns_id_t,xml_token_t,xml_context_base *)663 void xlsx_conditional_format_context::end_child_context(xmlns_id_t /*ns*/, xml_token_t /*name*/, xml_context_base* /*child*/)
664 {
665 }
666
start_element(xmlns_id_t ns,xml_token_t name,const xml_attrs_t & attrs)667 void xlsx_conditional_format_context::start_element(xmlns_id_t ns, xml_token_t name, const xml_attrs_t& attrs)
668 {
669 xml_token_pair_t parent = push_stack(ns, name);
670
671 switch (name)
672 {
673 case XML_conditionalFormatting:
674 {
675 xml_element_expected(parent, NS_ooxml_xlsx, XML_worksheet);
676 std::for_each(attrs.begin(), attrs.end(), conditional_formatting_attr_parser(m_cond_format));
677 }
678 break;
679 case XML_cfRule:
680 {
681 xml_element_expected(parent, NS_ooxml_xlsx, XML_conditionalFormatting);
682 cfRule_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), cfRule_attr_parser(m_cond_format));
683 parser.set_type();
684 }
685 break;
686 case XML_cfvo:
687 {
688 cfvo_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), cfvo_attr_parser(m_pool));
689 m_cfvo_values.push_back(parser.get_values());
690 }
691 break;
692 case XML_dataBar:
693 {
694 xml_element_expected(parent, NS_ooxml_xlsx, XML_cfRule);
695 data_bar_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), data_bar_attr_parser());
696 parser.import_data(m_cond_format);
697 }
698 break;
699 case XML_iconSet:
700 {
701 xml_element_expected(parent, NS_ooxml_xlsx, XML_cfRule);
702 icon_set_attr_parser parser = std::for_each(attrs.begin(), attrs.end(), icon_set_attr_parser());
703 parser.import_data(m_cond_format);
704 }
705 break;
706 case XML_color:
707 {
708 for (const xml_token_attr_t& attr : attrs)
709 {
710 switch (attr.name)
711 {
712 case XML_rgb:
713 {
714 argb_color color;
715 if (to_rgb(attr.value, color.alpha, color.red, color.green, color.blue))
716 m_colors.push_back(color);
717 break;
718 }
719 default:
720 ;
721 }
722 }
723 }
724 break;
725 case XML_formula:
726 break;
727 case XML_colorScale:
728 break;
729 default:
730 warn_unhandled();
731 }
732 }
733
734 namespace {
735
import_cfvo(const cfvo_values & values,spreadsheet::iface::import_conditional_format & cond_format)736 void import_cfvo(const cfvo_values& values, spreadsheet::iface::import_conditional_format& cond_format)
737 {
738 if (!values.m_value.empty())
739 cond_format.set_formula(values.m_value.get(),values.m_value.size());
740 switch (values.m_type)
741 {
742 case cfvo_num:
743 cond_format.set_condition_type(spreadsheet::condition_type_t::value);
744 break;
745 case cfvo_percent:
746 cond_format.set_condition_type(spreadsheet::condition_type_t::percent);
747 break;
748 case cfvo_max:
749 cond_format.set_condition_type(spreadsheet::condition_type_t::max);
750 break;
751 case cfvo_min:
752 cond_format.set_condition_type(spreadsheet::condition_type_t::min);
753 break;
754 case cfvo_formula:
755 cond_format.set_condition_type(spreadsheet::condition_type_t::formula);
756 break;
757 case cfvo_percentile:
758 cond_format.set_condition_type(spreadsheet::condition_type_t::percentile);
759 break;
760 default:
761 break;
762 }
763 }
764
765 }
766
end_element(xmlns_id_t ns,xml_token_t name)767 bool xlsx_conditional_format_context::end_element(xmlns_id_t ns, xml_token_t name)
768 {
769 switch (name)
770 {
771 case XML_conditionalFormatting:
772 {
773 m_cond_format.commit_format();
774 }
775 break;
776 case XML_cfRule:
777 {
778 m_cond_format.commit_entry();
779 m_cfvo_values.clear();
780 m_colors.clear();
781 }
782 break;
783 case XML_cfvo:
784 break;
785 case XML_color:
786 break;
787 case XML_formula:
788 {
789 m_cond_format.set_formula(m_cur_str.get(), m_cur_str.size());
790 m_cond_format.commit_condition();
791 }
792 break;
793 case XML_dataBar:
794 {
795 if (m_colors.size() != 1)
796 throw general_error("invalid dataBar record");
797 if (m_cfvo_values.size() != 2)
798 throw general_error("invalid dataBar record");
799 argb_color& color = m_colors[0];
800 m_cond_format.set_databar_color_positive(color.alpha, color.red,
801 color.green, color.blue);
802 m_cond_format.set_databar_color_negative(color.alpha, color.red,
803 color.green, color.blue);
804 for (std::vector<cfvo_values>::const_iterator itr = m_cfvo_values.begin(); itr != m_cfvo_values.end(); ++itr) {
805 import_cfvo(*itr, m_cond_format);
806 m_cond_format.commit_condition();
807 }
808 }
809 break;
810 case XML_iconSet:
811 if (m_cfvo_values.size() < 2)
812 throw general_error("invalid iconSet record");
813 for (std::vector<cfvo_values>::const_iterator itr = m_cfvo_values.begin(); itr != m_cfvo_values.end(); ++itr) {
814 import_cfvo(*itr, m_cond_format);
815 m_cond_format.commit_condition();
816 }
817 break;
818 case XML_colorScale:
819 {
820 if (m_cfvo_values.size() < 2)
821 throw general_error("invalid colorScale record");
822 if (m_cfvo_values.size() != m_colors.size())
823 throw general_error("invalid colorScale record");
824 std::vector<argb_color>::const_iterator itrColor = m_colors.begin();
825 for (std::vector<cfvo_values>::const_iterator itr = m_cfvo_values.begin(); itr != m_cfvo_values.end(); ++itr, ++itrColor) {
826 import_cfvo(*itr, m_cond_format);
827 m_cond_format.set_color(itrColor->alpha, itrColor->red,
828 itrColor->green, itrColor->blue);
829 m_cond_format.commit_condition();
830 }
831 }
832 break;
833 default:
834 ;
835 }
836
837 m_cur_str.clear();
838 return pop_stack(ns, name);
839 }
840
characters(const pstring & str,bool transient)841 void xlsx_conditional_format_context::characters(const pstring& str, bool transient)
842 {
843 m_cur_str = str;
844 if (transient)
845 m_cur_str = m_pool.intern(m_cur_str).first;
846 }
847
848
849 }
850
851 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
852