diff --git a/src/JSON.cpp b/src/JSON.cpp index 57e7bf477..1c2b579e9 100644 --- a/src/JSON.cpp +++ b/src/JSON.cpp @@ -36,11 +36,11 @@ json::value* json::value::parse (Nibbler& nibbler) { json::value* v; - if ((v = json::object::parse (nibbler)) || - (v = json::array::parse (nibbler)) || - (v = json::string::parse (nibbler)) || - (v = json::number::parse (nibbler)) || - (v = json::literal::parse (nibbler))) + if ((v = json::object::parse (nibbler)) || + (v = json::array::parse (nibbler)) || + (v = json::string::parse (nibbler)) || + (v = json::number::parse (nibbler)) || + (v = json::literal::parse (nibbler))) return v; return NULL; @@ -61,7 +61,7 @@ std::string json::value::dump () //////////////////////////////////////////////////////////////////////////////// json::string::string (const std::string& other) { - *this = other; + _data = other; } //////////////////////////////////////////////////////////////////////////////// @@ -71,7 +71,7 @@ json::string* json::string::parse (Nibbler& nibbler) if (nibbler.getQuoted ('"', value, false)) { json::string* s = new json::string (); - *(std::string*)s = value; + s->_data = value; return s; } @@ -87,7 +87,7 @@ json::jtype json::string::type () //////////////////////////////////////////////////////////////////////////////// std::string json::string::dump () { - return std::string ("\"") + (std::string) *this + "\""; + return std::string ("\"") + _data + "\""; } //////////////////////////////////////////////////////////////////////////////// @@ -165,9 +165,7 @@ std::string json::literal::dump () json::array::~array () { std::vector ::iterator i; - for (i = ((std::vector *)this)->begin (); - i != ((std::vector *)this)->end (); - ++i) + for (i = _data.begin (); i != _data.end (); ++i) delete *i; } @@ -185,7 +183,7 @@ json::array* json::array::parse (Nibbler& nibbler) json::value* value; if ((value = json::value::parse (n))) { - arr->push_back (value); + arr->_data.push_back (value); value = NULL; // Not a leak. Looks like a leak. n.skipWS (); while (n.skip (',')) @@ -194,7 +192,7 @@ json::array* json::array::parse (Nibbler& nibbler) if ((value = json::value::parse (n))) { - arr->push_back (value); + arr->_data.push_back (value); n.skipWS (); } else @@ -232,11 +230,11 @@ std::string json::array::dump () output += "["; std::vector ::iterator i; - for (i = ((std::vector *)this)->begin (); - i != ((std::vector *)this)->end (); + for (i = _data.begin (); + i != _data.end (); ++i) { - if (i != ((std::vector *)this)->begin ()) + if (i != _data.begin ()) output += ","; output += (*i)->dump (); @@ -250,9 +248,7 @@ std::string json::array::dump () json::object::~object () { std::map ::iterator i; - for (i = ((std::map *)this)->begin (); - i != ((std::map *)this)->end (); - ++i) + for (i = _data.begin (); i != _data.end (); ++i) delete i->second; } @@ -271,7 +267,7 @@ json::object* json::object::parse (Nibbler& nibbler) json::value* value; if (json::object::parse_pair (n, name, value)) { - obj->insert (std::pair (name, value)); + obj->_data.insert (std::pair (name, value)); value = NULL; // Not a leak. Looks like a leak. n.skipWS (); @@ -281,7 +277,7 @@ json::object* json::object::parse (Nibbler& nibbler) if (json::object::parse_pair (n, name, value)) { - obj->insert (std::pair (name, value)); + obj->_data.insert (std::pair (name, value)); n.skipWS (); } else @@ -348,11 +344,9 @@ std::string json::object::dump () output += "{"; std::map ::iterator i; - for (i = ((std::map *)this)->begin (); - i != ((std::map *)this)->end (); - ++i) + for (i = _data.begin (); i != _data.end (); ++i) { - if (i != ((std::map *)this)->begin ()) + if (i != _data.begin ()) output += ","; output += "\"" + i->first + "\":"; diff --git a/src/JSON.h b/src/JSON.h index 7a3da7da7..21b13354f 100644 --- a/src/JSON.h +++ b/src/JSON.h @@ -38,12 +38,12 @@ namespace json { enum jtype { - j_value, - j_object, - j_array, - j_string, - j_number, - j_literal + j_value, // 0 + j_object, // 1 + j_array, // 2 + j_string, // 3 + j_number, // 4 + j_literal // 5 }; class value @@ -56,7 +56,7 @@ namespace json virtual std::string dump (); }; - class string : public value, public std::string + class string : public value { public: string () {} @@ -65,9 +65,12 @@ namespace json static string* parse (Nibbler&); jtype type (); std::string dump (); + + public: + std::string _data; }; - class number : public value, public std::string + class number : public value { public: number () : _dvalue (0.0) {} @@ -77,6 +80,7 @@ namespace json std::string dump (); operator double () const; + public: double _dvalue; }; @@ -89,11 +93,12 @@ namespace json jtype type (); std::string dump (); + public: enum literal_value {none, nullvalue, falsevalue, truevalue}; literal_value _lvalue; }; - class array : public value, public std::vector + class array : public value { public: array () {} @@ -101,9 +106,12 @@ namespace json static array* parse (Nibbler&); jtype type (); std::string dump (); + + public: + std::vector _data; }; - class object : public value, public std::map + class object : public value { public: object () {} @@ -112,6 +120,9 @@ namespace json static bool parse_pair (Nibbler&, std::string&, value*&); jtype type (); std::string dump (); + + public: + std::map _data; }; // Parser entry point. @@ -122,9 +133,6 @@ namespace json std::string decode (const std::string&); } -typedef std::vector json_array; -typedef std::map json_object; - typedef std::vector ::iterator json_array_iter; typedef std::map ::iterator json_object_iter; diff --git a/src/Task.cpp b/src/Task.cpp index a108f6784..ef2447865 100644 --- a/src/Task.cpp +++ b/src/Task.cpp @@ -121,11 +121,11 @@ Task::status Task::textToStatus (const std::string& input) //////////////////////////////////////////////////////////////////////////////// std::string Task::statusToText (Task::status s) { - if (s == Task::pending) return "pending"; // TODO i18n - else if (s == Task::completed) return "completed"; // TODO i18n - else if (s == Task::deleted) return "deleted"; // TODO i18n - else if (s == Task::recurring) return "recurring"; // TODO i18n - else if (s == Task::waiting) return "waiting"; // TODO i18n + if (s == Task::pending) return "pending"; + else if (s == Task::completed) return "completed"; + else if (s == Task::deleted) return "deleted"; + else if (s == Task::recurring) return "recurring"; + else if (s == Task::waiting) return "waiting"; return "pending"; } diff --git a/src/commands/CmdImport.cpp b/src/commands/CmdImport.cpp index 0b96337d5..bc028d068 100644 --- a/src/commands/CmdImport.cpp +++ b/src/commands/CmdImport.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -42,7 +43,7 @@ CmdImport::CmdImport () { _keyword = "import"; _usage = "task import [ ...]"; - _description = "Imports JSON files."; + _description = STRING_CMD_IMPORT_USAGE; _read_only = false; _displays_id = false; } @@ -94,36 +95,100 @@ int CmdImport::execute (std::string& output) // Parse the whole thing. json::value* root = json::parse (object); - std::cout << root->dump () - << "\n"; - - // For each object element... - json_object_iter i; - for (i = ((json_object*)root)->begin (); - i != ((json_object*)root)->end (); - ++i) - { - std::cout << "!!!\n"; - } - -/* - std::map ::iterator i; - for (i = ((std::map *)root)->begin (); - i != ((std::map *)root)->end (); - ++i) + if (root->type () == json::j_object) { + json::object* root_obj = (json::object*)root; Task task; - std::cout << "!!!\n"; + task.set ("uuid", uuid ()); - // TODO Navigate each object. + // For each object element... + json_object_iter i; + for (i = root_obj->_data.begin (); + i != root_obj->_data.end (); + ++i) + { + // If the attribute is a recognized column. + Column* col = context.columns[i->first]; + if (col) + { + // Any specified id is ignored. + if (i->first == "id") + ; + + // Dates are converted from ISO to epoch. + else if (col->type () == "date") + { + Date d (unquoteText (i->second->dump ())); + task.set (i->first, d.toEpochString ()); + } + + // Other types are simply added. + else + task.set (i->first, unquoteText (i->second->dump ())); + } + + // Several attributes do not have columns. + // mask + // imask + // parent + else + { + // Annotations are an array of JSON objects with 'entry' and + // 'description' values and must be converted. + if (i->first == "annotations") + { + std::vector annos; + + json::array* atts = (json::array*)i->second; + json_array_iter annotations; + for (annotations = atts->_data.begin (); + annotations != atts->_data.end (); + ++annotations) + { + json::object* annotation = (json::object*)*annotations; + json::string* when = (json::string*)annotation->_data["entry"]; + json::string* what = (json::string*)annotation->_data["description"]; + + std::string name = "annotation_" + Date (when->_data).toEpochString (); + + annos.push_back (Att (name, what->_data)); + } + + task.setAnnotations (annos); + } + + // These must be imported, but are not represented by Column + // objects. + else if (i->first == "mask" || + i->first == "imask" || + i->first == "parent") + { + task.set (i->first, unquoteText (i->second->dump ())); + } + else + throw std::string ("Unrecognized attribute '") + i->first + "'"; + } + } + + task.validate (); + + // TODO Verify uuid is unique, to prevent double-import. + + std::cout << " " + << task.get ("uuid") + << " " + << task.get ("description") + << "\n"; + context.tdb2.add (task); } -*/ + else + throw std::string ("Not a JSON object: ") + *line; delete root; - root = NULL; } } + context.tdb2.commit (); return rc; } diff --git a/src/en-US.h b/src/en-US.h index f7f35fd67..dd3c6fd31 100644 --- a/src/en-US.h +++ b/src/en-US.h @@ -308,6 +308,7 @@ #define STRING_CMD_DENO_NONE "The specified task has no annotations that can be deleted." #define STRING_CMD_DENO_FOUND "Found annotation '{1}' and deleted it." #define STRING_CMD_DENO_NOMATCH "Did not find any matching annotation to be deleted for '{1}'." +#define STRING_CMD_IMPORT_USAGE "Imports JSON files." // Config #define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."