From 6f4f468d0d2917d3880cf990d446e0bab426a2e6 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Mon, 1 Feb 2016 01:10:11 -0500 Subject: [PATCH] ColUDA: Split ColUDA into ColUDA{String,Numeric,Date,Duration} to make use of ColType*::modify --- src/columns/ColUDA.cpp | 369 ++++++++++++++++++++++++++++++++++------- src/columns/ColUDA.h | 58 ++++++- src/columns/Column.cpp | 62 ++++--- 3 files changed, 401 insertions(+), 88 deletions(-) diff --git a/src/columns/ColUDA.cpp b/src/columns/ColUDA.cpp index e0221dc9b..c4a45e1af 100644 --- a/src/columns/ColUDA.cpp +++ b/src/columns/ColUDA.cpp @@ -36,19 +36,18 @@ extern Context context; //////////////////////////////////////////////////////////////////////////////// -ColumnUDA::ColumnUDA () +ColumnUDAString::ColumnUDAString () { _name = ""; - _type = "string"; _style = "default"; _label = ""; _uda = true; - _hyphenate = (_type == "string") ? true : false; + _hyphenate = true; _styles = {_style, "indicator"}; } //////////////////////////////////////////////////////////////////////////////// -bool ColumnUDA::validate (std::string& value) +bool ColumnUDAString::validate (std::string& value) { // No restrictions. if (_values.size () == 0) @@ -66,7 +65,7 @@ bool ColumnUDA::validate (std::string& value) //////////////////////////////////////////////////////////////////////////////// // Set the minimum and maximum widths for the value. // -void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximum) +void ColumnUDAString::measure (Task& task, unsigned int& minimum, unsigned int& maximum) { minimum = maximum = 0; @@ -77,35 +76,9 @@ void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximu std::string value = task.get (_name); if (value != "") { - if (_type == "date") - { - // Determine the output date format, which uses a hierarchy of definitions. - // rc.report..dateformat - // rc.dateformat.report - // rc.dateformat - ISO8601d date ((time_t) strtol (value.c_str (), NULL, 10)); - std::string format = context.config.get ("report." + _report + ".dateformat"); - if (format == "") - format = context.config.get ("dateformat.report"); - if (format == "") - format = context.config.get ("dateformat"); - - minimum = maximum = ISO8601d::length (format); - } - else if (_type == "duration") - { - minimum = maximum = ISO8601p (value).format ().length (); - } - else if (_type == "string") - { - std::string stripped = Color::strip (value); - maximum = longestLine (stripped); - minimum = longestWord (stripped); - } - else if (_type == "numeric") - { - minimum = maximum = value.length (); - } + std::string stripped = Color::strip (value); + maximum = longestLine (stripped); + minimum = longestWord (stripped); } } else if (_style == "indicator") @@ -127,7 +100,7 @@ void ColumnUDA::measure (Task& task, unsigned int& minimum, unsigned int& maximu } //////////////////////////////////////////////////////////////////////////////// -void ColumnUDA::render ( +void ColumnUDAString::render ( std::vector & lines, Task& task, int width, @@ -138,36 +111,304 @@ void ColumnUDA::render ( if (_style == "default") { std::string value = task.get (_name); - if (_type == "date") - { - // Determine the output date format, which uses a hierarchy of definitions. - // rc.report..dateformat - // rc.dateformat.report - // rc.dateformat. - std::string format = context.config.get ("report." + _report + ".dateformat"); - if (format == "") - { - format = context.config.get ("dateformat.report"); - if (format == "") - format = context.config.get ("dateformat"); - } + std::vector raw; + wrapText (raw, value, width, _hyphenate); - renderStringLeft (lines, width, color, ISO8601d ((time_t) strtol (value.c_str (), NULL, 10)).toString (format)); - } - else if (_type == "duration") - renderStringRight (lines, width, color, ISO8601p (value).format ()); - - else if (_type == "string") - { - std::vector raw; - wrapText (raw, value, width, _hyphenate); - - for (auto& i : raw) - renderStringLeft (lines, width, color, i); - } - - else if (_type == "numeric") - renderStringRight (lines, width, color, value); + for (auto& i : raw) + renderStringLeft (lines, width, color, i); + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + renderStringRight (lines, width, color, indicator); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +ColumnUDANumeric::ColumnUDANumeric () +{ + _name = ""; + _type = "numeric"; + _style = "default"; + _label = ""; + _uda = true; + _hyphenate = false; + _styles = {_style, "indicator"}; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ColumnUDANumeric::validate (std::string& value) +{ + // No restrictions. + if (_values.size () == 0) + return true; + + // Look for exact match value. + for (auto& i : _values) + if (i == value) + return true; + + // Fail if not found. + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Set the minimum and maximum widths for the value. +// +void ColumnUDANumeric::measure (Task& task, unsigned int& minimum, unsigned int& maximum) +{ + minimum = maximum = 0; + + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + if (value != "") + minimum = maximum = value.length (); + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + minimum = maximum = utf8_width (indicator); + } + else + minimum = maximum = 0; + } + else + throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); + } +} + +//////////////////////////////////////////////////////////////////////////////// +void ColumnUDANumeric::render ( + std::vector & lines, + Task& task, + int width, + Color& color) +{ + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + renderStringRight (lines, width, color, value); + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + renderStringRight (lines, width, color, indicator); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +ColumnUDADate::ColumnUDADate () +{ + _name = ""; + _type = "date"; + _style = "default"; + _label = ""; + _uda = true; + _hyphenate = false; + _styles = {_style, "indicator"}; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ColumnUDADate::validate (std::string& value) +{ + // No restrictions. + if (_values.size () == 0) + return true; + + // Look for exact match value. + for (auto& i : _values) + if (i == value) + return true; + + // Fail if not found. + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Set the minimum and maximum widths for the value. +// +void ColumnUDADate::measure (Task& task, unsigned int& minimum, unsigned int& maximum) +{ + minimum = maximum = 0; + + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + if (value != "") + { + // Determine the output date format, which uses a hierarchy of definitions. + // rc.report..dateformat + // rc.dateformat.report + // rc.dateformat + ISO8601d date ((time_t) strtol (value.c_str (), NULL, 10)); + std::string format = context.config.get ("report." + _report + ".dateformat"); + if (format == "") + format = context.config.get ("dateformat.report"); + if (format == "") + format = context.config.get ("dateformat"); + + minimum = maximum = ISO8601d::length (format); + } + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + minimum = maximum = utf8_width (indicator); + } + else + minimum = maximum = 0; + } + else + throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); + } +} + +//////////////////////////////////////////////////////////////////////////////// +void ColumnUDADate::render ( + std::vector & lines, + Task& task, + int width, + Color& color) +{ + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + + // Determine the output date format, which uses a hierarchy of definitions. + // rc.report..dateformat + // rc.dateformat.report + // rc.dateformat. + std::string format = context.config.get ("report." + _report + ".dateformat"); + if (format == "") + { + format = context.config.get ("dateformat.report"); + if (format == "") + format = context.config.get ("dateformat"); + } + + renderStringLeft (lines, width, color, ISO8601d ((time_t) strtol (value.c_str (), NULL, 10)).toString (format)); + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + renderStringRight (lines, width, color, indicator); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +ColumnUDADuration::ColumnUDADuration () +{ + _name = ""; + _type = "duration"; + _style = "default"; + _label = ""; + _uda = true; + _hyphenate = false; + _styles = {_style, "indicator"}; +} + +//////////////////////////////////////////////////////////////////////////////// +bool ColumnUDADuration::validate (std::string& value) +{ + // No restrictions. + if (_values.size () == 0) + return true; + + // Look for exact match value. + for (auto& i : _values) + if (i == value) + return true; + + // Fail if not found. + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// Set the minimum and maximum widths for the value. +// +void ColumnUDADuration::measure (Task& task, unsigned int& minimum, unsigned int& maximum) +{ + minimum = maximum = 0; + + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + if (value != "") + minimum = maximum = ISO8601p (value).format ().length (); + } + else if (_style == "indicator") + { + if (task.has (_name)) + { + auto indicator = context.config.get ("uda." + _name + ".indicator"); + if (indicator == "") + indicator = "U"; + + minimum = maximum = utf8_width (indicator); + } + else + minimum = maximum = 0; + } + else + throw format (STRING_COLUMN_BAD_FORMAT, _name, _style); + } +} + +//////////////////////////////////////////////////////////////////////////////// +void ColumnUDADuration::render ( + std::vector & lines, + Task& task, + int width, + Color& color) +{ + if (task.has (_name)) + { + if (_style == "default") + { + std::string value = task.get (_name); + renderStringRight (lines, width, color, ISO8601p (value).format ()); } else if (_style == "indicator") { diff --git a/src/columns/ColUDA.h b/src/columns/ColUDA.h index 43272466d..0e7b2f01e 100644 --- a/src/columns/ColUDA.h +++ b/src/columns/ColUDA.h @@ -27,12 +27,64 @@ #ifndef INCLUDED_COLUDA #define INCLUDED_COLUDA -#include +#include +#include +#include +#include -class ColumnUDA : public Column +//////////////////////////////////////////////////////////////////////////////// +class ColumnUDAString : public ColumnTypeString { public: - ColumnUDA (); + ColumnUDAString (); + bool validate (std::string&); + void measure (Task&, unsigned int&, unsigned int&); + void render (std::vector &, Task&, int, Color&); + +public: + std::vector _values; + +private: + bool _hyphenate; +}; + +//////////////////////////////////////////////////////////////////////////////// +class ColumnUDANumeric : public ColumnTypeNumeric +{ +public: + ColumnUDANumeric (); + bool validate (std::string&); + void measure (Task&, unsigned int&, unsigned int&); + void render (std::vector &, Task&, int, Color&); + +public: + std::vector _values; + +private: + bool _hyphenate; +}; + +//////////////////////////////////////////////////////////////////////////////// +class ColumnUDADate : public ColumnTypeDate +{ +public: + ColumnUDADate (); + bool validate (std::string&); + void measure (Task&, unsigned int&, unsigned int&); + void render (std::vector &, Task&, int, Color&); + +public: + std::vector _values; + +private: + bool _hyphenate; +}; + +//////////////////////////////////////////////////////////////////////////////// +class ColumnUDADuration : public ColumnTypeDuration +{ +public: + ColumnUDADuration (); bool validate (std::string&); void measure (Task&, unsigned int&, unsigned int&); void render (std::vector &, Task&, int, Color&); diff --git a/src/columns/Column.cpp b/src/columns/Column.cpp index ce9b01ea7..c5ef06902 100644 --- a/src/columns/Column.cpp +++ b/src/columns/Column.cpp @@ -175,29 +175,49 @@ void Column::uda (std::map & all) //////////////////////////////////////////////////////////////////////////////// Column* Column::uda (const std::string& name) { - ColumnUDA* c = new ColumnUDA (); - c->_name = name; + auto type = context.config.get ("uda." + name + ".type"); + auto label = context.config.get ("uda." + name + ".label"); + auto values = context.config.get ("uda." + name + ".values"); - std::string key = "uda." + name + ".type"; - c->_type = context.config.get (key); - if (c->_type == "") - context.error (format (STRING_UDA_TYPE_MISSING, name)); + if (type == "string") + { + auto c = new ColumnUDAString (); + c->_name = name; + c->_label = label; + if (values != "") + split (c->_values, values, ','); + return c; + } + else if (type == "numeric") + { + auto c = new ColumnUDANumeric (); + c->_name = name; + c->_label = label; + if (values != "") + split (c->_values, values, ','); + return c; + } + else if (type == "date") + { + auto c = new ColumnUDADate (); + c->_name = name; + c->_label = label; + if (values != "") + split (c->_values, values, ','); + return c; + } + else if (type == "duration") + { + auto c = new ColumnUDADuration (); + c->_name = name; + c->_label = label; + if (values != "") + split (c->_values, values, ','); + return c; + } - if (c->_type != "string" && - c->_type != "date" && - c->_type != "duration" && - c->_type != "numeric") - context.error (STRING_UDA_TYPE); - - key = "uda." + name + ".label"; - if (context.config.get (key) != "") - c->_label = context.config.get (key); - - key = "uda." + name + ".values"; - if (context.config.get (key) != "") - split (c->_values, context.config.get (key), ','); - - return c; + throw std::string (STRING_UDA_TYPE); + return NULL; } ////////////////////////////////////////////////////////////////////////////////