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